Почему Чар.Isdigit возвращает true для символов, которые не могут быть проанализированы в int?

я часто использую Char.IsDigit чтобы проверить, если char - это цифра, которая особенно удобна в запросах LINQ для предварительной проверки int.Parse а вот: "123".All(Char.IsDigit).

но есть символы, которые являются цифрами, но которые не могут быть разобраны для int как ۵.

// true
bool isDigit = Char.IsDigit('۵'); 

var cultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
int num;
// false
bool isIntForAnyCulture = cultures
    .Any(c => int.TryParse('۵'.ToString(), NumberStyles.Any, c, out num)); 

почему это? Мой int.Parse-precheck через неправильные?

есть 310 символов, которые являются цифрами:

List<char> digitList = Enumerable.Range(0, UInt16.MaxValue)
   .Select(i => Convert.ToChar(i))
   .Where(c => Char.IsDigit(c))
   .ToList(); 

вот реализация Char.IsDigit в .NET 4 (ILSpy):

public static bool IsDigit(char c)
{
    if (char.IsLatin1(c))
    {
        return c >= '0' && c <= '9';
    }
    return CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.DecimalDigitNumber;
}

так почему же есть символы, которые принадлежат DecimalDigitNumberкатегория("десятичный знак, то есть символ в диапазоне от 0 до 9...") который не может быть проанализирован на int в любой культуре?

2 ответов


это потому, что он проверяет все цифры в категории Unicode "число, десятичная цифра", как указано здесь:

http://www.fileformat.info/info/unicode/category/Nd/list.htm

это не означает, что это допустимый числовой символ в текущей локали. Фактически используя int.Parse(), вы можете анализировать только обычные английские цифры, независимо от настройки локали.

например,не работа:

int test = int.Parse("٣", CultureInfo.GetCultureInfo("ar"));

хотя ٣ является допустимым арабским цифровым символом, а" ar " - идентификатором арабского языка.

статья Microsoft "How to: Parse Unicode Digits" гласит:

единственными цифрами Юникода, которые .NET Framework анализирует как десятичные, являются цифры ASCII от 0 до 9, заданные значениями кода U+0030 до U+0039. Платформа .NET Framework анализирует все остальные цифры Юникода как символы.

обратите внимание, что вы можете использовать char.GetNumericValue() для преобразования числового символа юникода в его числовой эквивалент в виде двойника.

причина, по которой возвращаемое значение является двойным, а не int, заключается в таких вещах:

Console.WriteLine(char.GetNumericValue('¼')); // Prints 0.25

вы можете использовать что-то вроде этого, чтобы преобразовать все числовые символы в строке в их эквивалент ASCII:

public string ConvertNumericChars(string input)
{
    StringBuilder output = new StringBuilder();

    foreach (char ch in input)
    {
        if (char.IsDigit(ch))
        {
            double value = char.GetNumericValue(ch);

            if ((value >= 0) && (value <= 9) && (value == (int)value))
            {
                output.Append((char)('0'+(int)value));
                continue;
            }
        }

        output.Append(ch);
    }

    return output.ToString();
}

десятичные цифры от 0 до 9, но они имеют много представлений в Unicode. От Википедия:

десятичные цифры повторяются в 23 отдельных блоков

MSDN указывает что .NET анализирует только латинские цифры:

, только цифры признанных методов синтаксического анализа основных цифр 0-9 с кодовыми точками от U+0030 до U+0039