文字列の大文字小文字処理
実は結構厄介な問題を抱えている。
文字列の大文字小文字の判定・変換・ソート順にはロケールが影響するケースがある。(要注意)
トルコ語(ロケールID tr_TR)の大文字I(U+0049)と小文字ı(U+0131)、大文字İ(U+0130)と小文字i (U+0069)
ドイツ語のエスツェットはもともと小文字 ß(U+00DF)のみで、大文字化した時にはSSとなるのが正式だった。
つまり小文字化する時、SSは小文字 ß(U+00DF)に変換される(すべき)可能性がある。
2017年に、大文字のエスツェットẞ(U+1E9E)が正書法に採用された。
小文字エスツェット ß(U+00DF)が使えない環境では代用としてssを使ってもよいとされている。
ニュートラルやCロケールにすることで、この問題を避けることができる。
C/C++ の場合 setlocale を実行しなければCロケールであることが保証されている。
先に toupper, tolower を使っていて、後からロケール対応で setlocale を入れるなどするとハマる。
API によっては、ASCII の範囲外まで大文字小文字の変換がかかる。(多くの人には想定外の動作となる。)
ASCII と EBCDIC などとはコード体系が異なるので、対応する文字を演算で求めようとする場合は要注意。
C
table:C
isupper int(実質char) ロケール影響あり(LC_CTYPE)
islower int(実質char) ロケール影響あり(LC_CTYPE)
toupper int(実質char) ロケール影響あり(LC_CTYPE)
tolower int(実質char) ロケール影響あり(LC_CTYPE)
_toupper int(実質char) ロケール影響なし(ASCIIのみ、判断済みのみ) マクロ
_tolower int(実質char) ロケール影響なし(ASCIIのみ、判断済みのみ) マクロ
towupper wint_t(実質wchar_t) ロケール影響あり(LC_CTYPE)
towlower wint_t(実質wchar_t) ロケール影響あり(LC_CTYPE)
setlocale をしない限りは、"C"ロケールで動作する。(要注意)
文字列に対する tolower, toupper 相当のものがない。ループで1文字ずつ変換する必要がある。
_toupper は'a'~'z'の文字のみにしか使えない。(事前に islower で判断が必要)
isupper の実装
配列による単純なマッピング方式がそれなりに高速だが、メモリアクセスを必要とする。(map[c] & UPPER_FLAG)
範囲の判定だと、条件判断のペナルティが発生する。('A' <= c && c <= 'Z')
どちらが早いのかはパフォーマンス測定しないとハッキリしない。
Java
table:Java
String toUpperCase() ロケール影響あり
String toLowerCase() ロケール影響あり
String toUpperCase(Locale.ROOT) ロケール影響なし
String toLowerCase(Locale.ROOT) ロケール影響なし
JavaScript
ES5以降
table:javascript
String.prototype.toUpperCase 大文字化 環境依存(toLocaleUpperCase が定義されていればロケール影響なし)
String.prototype.toLowerCase 小文字化 環境依存(toLocaleLowerCase が定義されていればロケール影響なし)
String.prototype.toLocaleUpperCase 大文字化 ロケール指定がなければロケール影響あり
String.prototype.toLocaleLowerCase 小文字化 ロケール指定がなければロケール影響あり
toUpperCase, toLowerCase でロケール影響なしの場合、Unicode Character Database のマッピングに従う。
.NET
table:.NET
String.ToUpperInvariant ロケール影響なし
String.ToLowerInvariant ロケール影響なし
String.ToUpper ロケール影響あり
String.ToLower ロケール影響あり
CaltureInfo で InvariantCulture を指定する方法がある。
table:VB/VBA
UCase 文字列を大文字化する
LCase 文字列を小文字化する
参考
Unicode Character Database