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. lua中常量的实现及表的深拷贝实现

    废话:好久没在这里写博客了...主要原因是我买了个域名hanxi.info并在github上搭建了个人博客... lua中默认是没有c中的const常量的,在csdn上找到了一个使用setmetata ...

  2. chrome https添加信任

    在浏览器地址栏输入:chrome://net-internals/#hsts 然后到Add domain下,Domain添上诸如google.com和google.com.hk ,并勾选Include ...

  3. PowerShell定时记录操作系统行为

    作为系统管理员,有些时候是需要记录系统中的其他用户的一些操作行为的,例如:当系统管理员怀疑系统存在漏洞,且已经有被植入后门或者创建隐藏账户时,就需要对曾经登陆的用户进行监控,保存其打开或者操作过的文件 ...

  4. IPFS搭建分布式文件系统 - 访问控制

    IPFS 一个内容可寻址.对等的超媒体分发协议. IPFS网络中的节点形成分布式文件系统. 为什么要用IPFS? “IPFS and the Blockchain are a perfect matc ...

  5. STAF自动化测试框架

    STAF自动化测试框架介绍 http://baike.baidu.com/link?url=9oPZN3JntRakidI7xizqCbyGRISMvCKGfXHBB_WH7OAkKjAKZjq88q ...

  6. php 连接redis,并登录验证

    环境: centos7 上安装了redis, 同时安装了php的redis扩展 yum install redis yum install php-pecl-redis redis服务端设置了登录密码 ...

  7. python 字符串查找

    python 字符串查找有4个方法,1 find,2 index方法,3 rfind方法,4 rindex方法. 1 find()方法: )##从下标1开始,查找在字符串里第一个出现的子串:返回结果3 ...

  8. 如何使用MVC编写Winform程序代码

    efwplus开源框架官网:www.efwplus.cn 前提:业务分析设计已完成,界面设计完成   1.代码结构划分 1)界面层:FrmSugeryApplyList.ISugeryApplyLis ...

  9. [原]Android打包之Gradle打包

    最近尝试了一下Android的Gradle打包,发现确实比Ant打包会方便很多,特此记录下来. 注:android的gradle现在插件的版本已经是0.14.3了,对于一些老的方法和api,有一些已经 ...

  10. Unity 全面理解加载和内存管理

    最近一直在和这些内容纠缠,把心得和大家共享一下: Unity里有两种动态加载机制:一是Resources.Load,一是通过AssetBundle,其实两者本质上我理解没有什么区别.Resources ...