1、起因

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

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

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

2、IsDigit函数

查阅MSDN,告知该函数是判断字符是Unicode的十进制数字的函数。在查看其源代码

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

第一行的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函数又是何物?

先看看这个函数的定义

public static bool IsNumber(char c)
{
if (!IsLatin1(c)) return CheckNumber(CharUnicodeInfo.GetUnicodeCategory(c));
if (!IsAscii(c)) return CheckNumber(GetLatin1UnicodeCategory(c));
return c >= '' && c <= '';
}
internal static bool CheckNumber(UnicodeCategory uc)
{
switch (uc)
{
case UnicodeCategory.DecimalDigitNumber:
case UnicodeCategory.LetterNumber:
case UnicodeCategory.OtherNumber:
return true;
}
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);
if (!(e.KeyChar >= '' && e.KeyChar <= '') && e.KeyChar != Delete)
{
e.Handled = true;
}
}

别误用IsDigit与IsNumber函数的更多相关文章

  1. 别误用IsDigit与IsNumber函数(转)

    1.起因 最近发现程序中有一段控制TextBox数字输入的代码,相信大家都不会太陌生,如下: void int_KeyPress(object sender, KeyPressEventArgs e) ...

  2. Difference between Char.IsDigit() and Char.IsNumber() in C#

    http://stackoverflow.com/questions/228532/difference-between-char-isdigit-and-char-isnumber-in-c-sha ...

  3. 【C#遗补】之Char.IsDigit和Char.IsNumber的区别

    原文:[C#遗补]之Char.IsDigit和Char.IsNumber的区别 Char中IsDigit和IsNumber的两个方法都是用来判断字符是否是数字的,那他们有什么区别 IsDigit    ...

  4. isdigit函数

    isdigit是计算机应用C语言中的一个函数,主要用于检查参数c是否为阿拉伯数字0到9. 相关函数 isdigit 表头文件 #include <ctype.h>(C语言),#includ ...

  5. PB函数大全

    PB函数大全 Abs()功能计算绝对值.语法Abs ( n )参数n:要得到绝对值的数值型变量或表达式返回值返回值的数据类型与n的数据类型相同,函数执行成功时返回n的绝对值.如果参数n的值为NULL, ...

  6. C#操作Excel的函数

    对于Excel的数据处理功能,大家都已经了解. 我们经常需要将数据导入到Excel,或直接打开Excel文档,读写文件操作,这需要用到ExcelHelper类,有了这个类,这些操作大大的减少我们工作量 ...

  7. Linux常用C函数---字符测试篇

    函数讲解部分参考http://net.pku.edu.cn/~yhf/linux_c/ isalnum(测试字符是否为英文或数字) 相关函数 isalpha,isdigit,islower,isupp ...

  8. salesforce 零基础学习(六十六)VF页面应善于使用变量和函数(二)常用函数的使用

    上一篇介绍VF中常用的变量,此篇主要内容为VF页面可以直接使用的函数,主要包括Date相关函数,Text相关函数,Information相关函数以及logic相关函数,其他相关函数,比如math相关函 ...

  9. 总结C语言字符检测函数:isalnum、isalpha...

    前言:最近一直在刷leetcode的题,用到isalnum函数,用man手册查找了一下,总共有13个相关函数如下: #include <ctype.h> int isalnum(int c ...

随机推荐

  1. “You must not call setTag() on a view Glide is targeting” 解决

    报错原因大致是因为Glide加载的iamgeView调用了setTag()方法导致的错误, 因为Glide已经默认为ImageView设置的Tag. 解决办法:自定义一个Application,在里面 ...

  2. Tomcat抛出异常:ClientAbortException: java.net.SocketException: Connection

    在做一个小网站的时候,写了一个通过servlet实现文件下载功能的页面.当我点击超级练级,弹出下载对话框,点击保存正常下载,不会出现任何问题,当我我点击取消,服务器端就出现如下提示: ClientAb ...

  3. 基本的文件 I/O

    基本的文件 I/O MSDN 抽象基类 Stream 支持读取和写入字节.Stream 集成了异步支持.其默认实现根据其相应的异步方法来定义同步读取和写入,反之亦然. 所有表示流的类都是从 Strea ...

  4. 解决oracle 端口 1521 本机127可通 其他ip不通

    http://wenku.baidu.com/link?url=8tRGGObqgLd6-yqprioIZSyluu9K0BgA29Lhx7F57pVDIHbMHVDNTa_SlEmVugGT4QJO ...

  5. WPF中如何用代码触发按钮Click处理

    btnOk.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));

  6. shell来start、stop、restart应用程序模板

    这里使用shell中的case语法: case分支语句格式如下: case $变量名 in 模式1) 命令列表 ;; 模式2) 命令列表 ;; *) ;; esac case行尾必须为单词“in”,每 ...

  7. mono+jexus 验证码不显示:System.Drawing

    System.ArgumentException The requested FontFamily could not be found [GDI+ status: FontFamilyNotFoun ...

  8. osgi: HttpService A null service reference is not allowed.

    最近在学习osgi,在练习HttpService的过程中,一直出现“A null service reference is not allowed”这样的报错,代码本身没有问题,在网上也搜了不少地方, ...

  9. C++:不同类型的指针的本质与差异

    转自:http://blog.csdn.net/richerg85/article/details/10076365 指针的类型(The Type of a Pointer)            一 ...

  10. java框架篇---spring hibernate整合

    在会使用hibernate 和spring框架后 两个框架的整合就变的相当容易了, 为什么要整合Hibernate?1.使用Spring的IOC功能管理SessionFactory对象 LocalSe ...