char.IsDigit() と
正規表現の"\d" は、半角数字にマッチする。
が、それだけでなく、
UNICODEカテゴリ"Nd"(Number, Decimal Digit) にもマッチする。
上記を意識して使わないと、高確率でバグを仕込んでしまう。
例えば、日本語システムだと全角数字("0" ~ "9")の入力が想定できるため、半角数字と区別する必要がある場合に、これらを使用するとバグる。
他に、これらを使ってチェックし、
int.Parse() に投げるなども NG。
※普通は、
int.TryParse() 推奨
UNICODEカテゴリ"Nd"にマッチすることの検証
[検証コード]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
using System;
using System.Globalization;
using System.Text.RegularExpressions;
static class Program
{
static void Main()
{
foreach( var point in DigitZeroPoints ){
for( var c = point; c < point + 10; c++ ){
var char_isdigit = char.IsDigit(c);
var regex_isdigit = Regex.IsMatch(c.ToString(), @"\d");
if( !char_isdigit || !regex_isdigit ){
Console.WriteLine(
"{0:X4} - char={1} regex={2} category={3}",
(int)c, char_isdigit, regex_isdigit,
CharUnicodeInfo.GetUnicodeCategory(c));
}
}
}
}
private static readonly char[] DigitZeroPoints = new[] {
'\u0030',
'\u0660',
'\u06F0',
'\u07C0',
'\u0966',
'\u09E6',
'\u0A66',
'\u0AE6',
'\u0B66',
'\u0BE6',
'\u0C66',
'\u0CE6',
'\u0D66',
'\u0E50',
'\u0ED0',
'\u0F20',
'\u1040',
'\u1090',
'\u17E0',
'\u1810',
'\u1946',
'\u19D0',
'\u1A80',
'\u1A90',
'\u1B50',
'\u1BB0',
'\u1C40',
'\u1C50',
'\uA620',
'\uA8D0',
'\uA900',
'\uA9D0',
'\uAA50',
'\uABF0',
'\uFF10',
};
}
[結果]
1A80 - char=False regex=False category=OtherNotAssigned
:
1A89 - char=False regex=False category=OtherNotAssigned
1A90 - char=False regex=False category=OtherNotAssigned
:
1A99 - char=False regex=False category=OtherNotAssigned
A9D0 - char=False regex=False category=OtherNotAssigned
:
A9D9 - char=False regex=False category=OtherNotAssigned
ABF0 - char=False regex=False category=OtherNotAssigned
:
ABF9 - char=False regex=False category=OtherNotAssigned
TAI THAM HORA DIGIT (1A80~9)、TAI THAM THAM DIGIT (1A90~9)、JAVANESE DIGIT (A9D0~9)、MEETEI MAYEK DIGIT (ABF0~9) が数字文字として判定されず、UNICODEカテゴリが"Cn"(Other, Not Assigned) となった。
原因は、判定されなかった文字の UNICODE バージョンは 5.2.0 で、Windows7/.NET 4.0 の UNICODE バージョンは 5.1 だからである。(参考:
.NET の UNICODE バージョン)
環境がないので検証できないが、Windows 8/.NET 4.5 なら数字文字として判定されるはず。
おまけ
半角数字のみを判定したい場合は、下記を使っている。
1
2
3
4
public static bool IsAsciiDigit(this char c)
{
return '0' <= c && c <= '9';
}
正規表現の場合
1
2
3
4
5
6
7
var regex_isdigit = Regex.IsMatch(c.ToString(), "[0-9]");
var regex_isdigit = Regex.IsMatch(c.ToString(), @"\d", RegexOptions.ECMAScript);
検証環境
Windows 7 64bit/Visual Studio 2010 SP1/.NET 4.0