在我的工作中听到有人使用String.toLowerCase()
将不区分大小写的代码存储在数据库中以便进行搜索时,我有一个epic fail时刻想到它可能出错的方式:
Unicode版本会影响哪些技术?
我是否需要担心Oracle或SQL Server(或其他供应商)更改其unicode版本并导致我的某个区域设置不会导致相同的低位或高位字符转换?
我该如何管理?我被确保使用数据库转换的“简单性”所诱惑,但是当有升级时,它将成为同样的问题。
答案 0 :(得分:34)
您不希望存储字符串的小写版本“for searchability”!!
这完全是错误的做法。您正在对Unicode套管的工作方式做出不公正和不正确的假设。
这就是为什么Unicode为字符串定义了一个名为casefold的单独的东西,不同于三种不同的情况(小写,标题和大写)。
如果你使用小写而不是casefold,这里有十个不同的例子你会做错的事:
ORIGINAL CASEFOLD LOWERCASE TITLECASE UPPERCASE
========================================================================
efficient efficient efficient Efficient EFFICIENT
flour flour flour Flour FLOUR
poſt post poſt Poſt POST
poſt post poſt Poſt POST
ſtop stop ſtop Stop STOP
tschüß tschüss tschüß Tschüß TSCHÜSS
weiß weiss weiß Weiß WEISS
WEIẞ weiss weiß Weiß WEIẞ
στιγμας στιγμασ στιγμας Στιγμας ΣΤΙΓΜΑΣ
ᾲ στο διάολο ὰι στο διάολο ᾲ στο διάολο Ὰͅ Στο Διάολο ᾺΙ ΣΤΟ ΔΙΆΟΛΟ
是的,我知道耻辱的复数是耻辱而不是耻辱;我试图显示最终的sigma问题。 ζ和σ都是大写sigma的有效小写版本Σ。如果你存储“只是小写”,那么你会得到错误的东西。
如果您使用的是Java Pattern
类,则必须同时指定CASE_INSENSITIVE
和UNICODE_CASE
,但仍然无法正确使用这些类,因为虽然Java使用完整的casemapping,但它仅使用简单的案例折叠。 这是一个问题。
至于突厥语言,是的,突厥语确实有一个特殊的案例。例如,İstanbul有一个只是ı̇stanbul的突厥语案例折叠,而不是你应该得到的伊斯坦布尔。因为我确信那些看起来不合适你,我会用非ASCII的命名字符拼写出来;在更简洁的术语中,"\N{LATIN CAPITAL LETTER I WITH DOT ABOVE}stanbul"
的突厥语案例翻译为"\N{LATIN SMALL LETTER DOTLESS I}\N{COMBINING DOT ABOVE}stanbul"
而不是"i\N{COMBINING DOT ABOVE}stanbul"
,而您通常会得到。{/ p>
如果您正在编写回归测试套件,那么还有几个表行:
[ "Henry Ⅷ", "henry ⅷ", "henry ⅷ", "Henry Ⅷ", "HENRY Ⅷ", ],
[ "I Work At Ⓚ", "i work at ⓚ", "i work at ⓚ", "I Work At Ⓚ", "I WORK AT Ⓚ", ],
[ "ʀᴀʀᴇ", "ʀᴀʀᴇ", "ʀᴀʀᴇ", "Ʀᴀʀᴇ", "ƦᴀƦᴇ", ],
[ "Ԧԧ", "ԧԧ", "ԧԧ", "Ԧԧ", "ԦԦ", ],
[ "", "", "", "", "", ],
[ "Ὰͅ", "ὰι", "ᾲ", "Ὰͅ", "ᾺΙ", ],
每列都是orig,fold,lc,tc和uc,就像我在上面的表格中一样。再次注意最后一行的casefold与其小写的不同。
答案 1 :(得分:1)
为toLowerCase()指定区域设置,而不是使用系统默认值。这可以防止更改系统区域设置。
至于Java未来版本中可能的unicode更改,我认为编写代码来处理这个问题并不值得。记录该产品支持Java 6并转向客户实际需要的功能。
答案 2 :(得分:0)
我认为最长期的解决方案是
显然,这需要在主要接口级别进行;如果我在java中进行这些更改,我更希望它是我唯一的数据接口机制(例如,其他技术人员不查询底层表存储)