为什么Char.IsDigit对于无法解析为int的字符返回true?

Tim*_*ter 9 .net c# string int character-encoding

我经常Char.IsDigit用来检查a 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)); 
Run Code Online (Sandbox Code Playgroud)

这是为什么?我的int.Parse-precheck Char.IsDigit因此不正确吗?

有310个字符是数字:

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

这是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;
}
Run Code Online (Sandbox Code Playgroud)

那么为什么有属于DecimalDigitNumber-category的字符("十进制数字字符,即0到9之间的字符......")无法int在任何文化中解析?

Mat*_*son 8

这是因为它正在检查Unicode"Number,Decimal Digit"类别中的所有数字,如下所示:

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

这并不意味着它是当前语言环境中的有效数字字符.实际上int.Parse(),无论语言环境设置如何,您都可以只解析正常的英文数字.

例如,这不起作用:

int test = int.Parse("?", CultureInfo.GetCultureInfo("ar"));
Run Code Online (Sandbox Code Playgroud)

即使?是有效的阿拉伯数字字符,"ar"也是阿拉伯语区域设置标识符.

微软文章"如何:解析Unicode数字"指出:

.NET Framework作为小数分析的唯一Unicode数字是ASCII数字0到9,由代码值U + 0030到U + 0039指定..NET Framework将所有其他Unicode数字解析为字符.

但请注意,您可以使用char.GetNumericValue()将unicode数字字符转换为数字等效字符作为double.

返回值是double而不是int的原因是因为这样的事情:

Console.WriteLine(char.GetNumericValue('¼')); // Prints 0.25
Run Code Online (Sandbox Code Playgroud)

您可以使用类似的东西将字符串中的所有数字字符转换为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();
}
Run Code Online (Sandbox Code Playgroud)