Почему Чар.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