IsDigit 및 IsNumber 함수를 오용하지 마십시오.

6347 단어 number
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;
            }
        }

언뜻 보기에는 아무런 문제가 없는 것 같지만, 0, 1, 2, 3 등 전각의 숫자를 입력할 수 있는 버그가 생겼다.오류의 근원은 바로 위 코드에서 사용된 IsDigit 함수이다. 그래서 다음과 같은 탐구가 생겼다. IsDigit 함수의 진면목을 살펴보자.
2. IsDigit 함수
MSDN을 찾아보면 함수가 유니코드의 십진수를 판단하는 함수임을 알 수 있습니다.소스 코드 보기
public static bool IsDigit(char c)
{
    if (!IsLatin1(c)) return CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.DecimalDigitNumber;
    return c >= '0' && c <= '9';
}

첫 줄의 IsLatin1 함수는 문자가 0~255인 것을 판단하는 함수인데 전각의 0, 1, 2, 3 등의 유니코드 인코딩은 이 범위에 있지 않기 때문에 아래의 코드를 집행했다.
CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.DecimalDigitNumber;

유니코드의 분류에서 반각의 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 >= '0' && c <= '9';
}
internal static bool CheckNumber(UnicodeCategory uc)
{
    switch (uc)
    {
        case UnicodeCategory.DecimalDigitNumber:
        case UnicodeCategory.LetterNumber:
        case UnicodeCategory.OtherNumber:
            return true;
    }
    return false;
}

IsDigit 함수와 비교하면 세 가지 차이가 있습니다: 1) 유니코드 Category가 하나 더 있습니다.LetterNumber 유형
2)유니코드 Category가 하나 더 있습니다.Othernumber 유형
3) IsAscii의 판단이 하나 더 생겼다(0~127)
IsNumber의 범위가 더 넓어진 것은 분명하다.다음은 IsNumber가 숫자로 간주하는 몇 가지 문자를 열거한다
UnicodeCategory.LetterNumber:Ⅰ、Ⅱ、Ⅲ
UnicodeCategory.OtherNumber:①、②、③
128~255 중 어떤 문자가 IsNumber에 의해 숫자로 여겨지는지 관심 있는 사람은 스스로 테스트할 수 있다.
테스트 방법은 이 함수를 이용할 수 있다: 시스템.Globalization.CharUnicodeInfo.Get Unicode Category (char c) 는 Unicode Category 형식으로 되돌아옵니다. IsNumber의 몇 가지 유형인지 보시면 알 수 있습니다.
4. 결론
위의 두 함수의 내부 실현을 규명하면 ASCII 숫자(0~9)인지 판단할 때 다음과 같은 몇 가지를 주의해야 한다.
1) IsDigit과 IsNumber 함수로 ASCII 숫자인지 아닌지를 판단할 수 없으며, 이 두 함수 모두 ASCII 이외의 일부 문자를 숫자로 간주할 수 있다.
2) 가능한 한 이런 방식으로 판단한다: c>='0'& c<='9'(물론 정규 표현식도 사용할 수 있다).
3) 숫자판단의 엄격성은 엄격함에서 느슨함까지 다음과 같다.
 c >= '0' && c <= '9' ⇒IsDigit ⇒IsNumber
4) 위의 버그 함수 수정을 끝으로
        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;
            }
        }

 
 

좋은 웹페이지 즐겨찾기