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. 画六边形-mat

    %% theta = linspace(0,2*pi,7); D=2; %边长 X=1; %中心横坐标 Y=2; %中心纵坐标 plot(D*cos(theta)+X,D*sin(theta) + Y ...

  2. 通过js看类似C#中的回掉

    我认为并行有两种形式,第一种是异步,第二种是多线程,目的都是为了实现并行,只不过异步和多线程都是手段而已 第一种异步 异步,执行完函数或方法后,不必阻塞性地等待返回值或消息,只需要向系统委托一个异步过 ...

  3. 生活科技两相宜:(一)Win7使用微软SkyDrive网盘简易教程

    今天得写一个Win7使用微软SkyDrive网盘的简易教程,主要是给我老婆看,顺便贴出来给大家共享一下:)    使用微软SkyDrive网盘有两个层次.一个是使用网页版,这个跟使用163或者QQ网盘 ...

  4. 《objective-c基础教程》学习笔记(九)—— Foundation框架介绍

    在之前的博文中,我们创建的项目文件的时候,默认都有引用#import <Foundation/foundation.h> 这个头文件.但是,之前我们对Foundation都没有展开介绍.这 ...

  5. 误删dpkg的/var/lib/dpkg/info文件夹的解决办法 zhuan

         今天安装软件时时,出现这样的错误提示:E: Sub-process /usr/bin/dpkg returned an error code (1)   上网查解决方案,被网上误导,一不小心 ...

  6. 读书笔记_Effective_C++_条款四十八:了解模板元编程

    作为模板部分的结束节,本条款谈到了模板元编程,元编程本质上就是将运行期的代价转移到编译期,它利用template编译生成C++源码,举下面阶乘例子: template <int N> st ...

  7. [原]编译Android源码过程中遇到的问题

    编译Android源码的过程参考Android官网介绍: 1.下载Android源码的步骤:https://source.android.com/source/downloading.html 2.编 ...

  8. XPS 15 9530使用Windows10频繁发生Intel HD Graphics 4600驱动奔溃的一种解决方法

    本人使用XPS 15 9530.集成显卡为Intel HD Graphics 4600.操作系统Windows 10 Pro,使用过程当中经常会发生集成显卡奔溃的问题,错误提示如下: Display ...

  9. ruby中字符的转换

    1.将表格名转成class名 classify "book_comments".classify => "BookComment"   2.class名转 ...

  10. sp_executesql 两种写法

    写法1: AlTER PROCEDURE TryAgain @ReturnValue int output AS declare @aa nvarchar(), @ForumID int, @coun ...