我经常使用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
-通过Char.IsDigit
预检查是否因此而不正确?
有310个字符是数字:
List<char> digitList = Enumerable.Range(0, UInt16.MaxValue)
.Select(i => Convert.ToChar(i))
.Where(c => Char.IsDigit(c))
.ToList();
以下是Char.IsDigit
在.NET4(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
呢?
这是因为它正在检查Unicode"数字,十进制数字"类别中的所有数字,如下所示:
http://www.fileformat.info/info/unicode/category/Nd/list.htm
这并不意味着它在当前区域设置中是一个有效的数字字符。事实上,使用int.Parse()
,无论语言环境设置如何,都只能解析正常的英文数字。
例如,这个不起作用:
int test = int.Parse("٣", CultureInfo.GetCultureInfo("ar"));
尽管٣
是一个有效的阿拉伯数字字符,并且"ar"是阿拉伯语言环境标识符。
微软的文章"如何:解析Unicode数字"指出:
.NET Framework解析为小数的唯一Unicode数字是ASCII数字0到9,由代码值U+0030到U+0039指定。.NET Framework将所有其他Unicode数字解析为字符。
但是,请注意,您可以使用char.GetNumericValue()
将unicode数字字符转换为等效于双精度的数字字符。
返回值是double而不是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