zoukankan      html  css  js  c++  java
  • 别误用IsDigit与IsNumber函数(转)

    1、起因

    最近发现程序中有一段控制TextBox数字输入的代码,相信大家都不会太陌生,如下:

    void int_KeyPress(object sender, KeyPressEventArgs e)
    {
        const char Delete = (char)8;
        if (!Char.IsDigit(e.KeyChar) && e.KeyChar != Delete)
        {
            e.Handled = true;
        }
    }

    乍一看,好像没有啥问题,但是却出现了一个bug,能够输入全角的数字,如:0、1、2、3等。错误的根源就是上面代码中用到的IsDigit函数,于是就有了下面的一番探究,让我们来看看IsDigit函数的真面目。

    2、IsDigit函数

    查阅MSDN,Char.IsDigit 方法是指示某个 Unicode 字符是否属于十进制数字类别。通过ILSpy查看其源代码:

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

    第一行的IsLatin1函数是判断字符是0~255的函数,而全角的0、1、2、3等的Unicode编码不在这个范围,于是就执行了下面这句代码:

    CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.DecimalDigitNumber;

    而对于Unicode的分类中,半角的1,2,3和全角的0、1、2、3等都被归为了DecimalDigitNumber,所以对于全角的数字,这个函数返回了true。
    还有一个函数IsNumber和IsDigit功能相似,我们是否可以用它来代替呢?看下面的分析

    3、IsNumber函数又是何物?

    MSDN的解释:Char.IsNumber 方法指示某个 Unicode 字符是否属于数字类别。

    这个函数的定义:

    [__DynamicallyInvokable]
    public static bool IsNumber(char c)
    {
        if (!char.IsLatin1(c))
        {
            return char.CheckNumber(CharUnicodeInfo.GetUnicodeCategory(c));
        }
        if (char.IsAscii(c))
        {
            return c >= '0' && c <= '9';
        }
        return char.CheckNumber(char.GetLatin1UnicodeCategory(c));
    }
    internal static bool CheckNumber(UnicodeCategory uc)
    {
        switch (uc)
        {
        case UnicodeCategory.DecimalDigitNumber:
        case UnicodeCategory.LetterNumber:
        case UnicodeCategory.OtherNumber:
            return true;
        default:
            return false;
        }
    }

    和IsDigit函数相比有3点区别:
    1)多了一个UnicodeCategory.LetterNumber类型

    2)多了一个UnicodeCategory.OtherNumber类型

    3)多了一个IsAscii的判断(0~127)

    很显然IsNumber的范围更广了。下面列举几种IsNumber认为是数字的字符

    UnicodeCategory.LetterNumber:Ⅰ、Ⅱ、Ⅲ

    UnicodeCategory.OtherNumber:①、②、③

    128~255中有哪些字符会被IsNumber认为是数字,有兴趣的可以自己去测试。

    测试的方法可以利用这个函数:System.Globalization.CharUnicodeInfo.GetUnicodeCategory(char c) ,返回的是一个UnicodeCategory类型,你可以看看是不是IsNumber的几个类型就知道了。

    4、结论

    搞清楚了上面这两个函数的内部实现,那么在判断是否是ASCII数字(0~9)的时候,我们就需要注意以下几点了。

    1)不能用IsDigit和IsNumber函数判断是否是ASCII数字,这两个函数都有可能把ASCII以外的某些字符当做是数字。

    2)尽量用这种方式判断: c >= '0' && c <= '9'(当然也可以用正则表达式)。

    3)数字判断的严格性,从严到松依次是:

     c >= '0' && c <= '9' IsDigit IsNumber

    4)修改上面的bug函数作为结束

    void int_KeyPress(object sender, KeyPressEventArgs e)
    {
        const char Delete = (char)8;
        if (!(e.KeyChar >= '0' && e.KeyChar <= '9') && e.KeyChar != Delete)
        {
            e.Handled = true;
        }
    }

      欢迎加群:.NET反编译|破解 群号:183569712(请输入验证信息:博客园). .NET反编译|破解 


    引用:

      别误用IsDigit与IsNumber函数

  • 相关阅读:
    Shortcut key for WPF
    Make webclient support upload the large file which are larger than 1G
    Decodes a QuotedPrintable encoded string
    C# USB Detection winform and WPF
    [转] 线程同步
    C# x86应用x64系统上读取x64位应用的注册表
    CSS Sprites图片拼合生成器实现思路
    python 复制文件
    Resources: Tips of Notepad++
    ASP.net MVC与RESTful ROA的思想还是有点区别的
  • 原文地址:https://www.cnblogs.com/Interkey/p/3694968.html
Copyright © 2011-2022 走看看