不区分大小写的存储和unicode兼容性

问题描述 投票:0回答:3

当我听说我的工作中有人使用

String.toLowerCase()
在数据库中存储不区分大小写的代码以实现可搜索性时,我有一个 史诗般的失败 时刻,思考它可能出错的方式:

  • 土耳其测试(特别是更改运行计算机上的区域设置)
  • Unicode 版本升级 - 我的意思是,谁知道这些东西?如果我升级到 Java 7,如果不区分大小写,我必须重新索引我的数据?

哪些技术受到 Unicode 版本的影响?

我是否需要担心 Oracle 或 SQL Server(或其他供应商)更改其 unicode 版本并导致我的区域设置之一不会导致相同的小写或大写字符转换?

我该如何处理这个问题?我对确保使用数据库转换的“简单性”很感兴趣,但是当升级时,也会出现同样的问题。

unicode compatibility
3个回答
42
投票

您不想存储字符串的小写版本“以供搜索”!!

这完全是错误的做法。您对 Unicode 大小写的工作原理做出了不公正且不正确的假设。

这就是为什么 Unicode 为字符串定义了一个单独的东西,称为大小写折叠,与三种不同的大小写(小写、标题大写和大写)不同。

这里有十个不同的例子如果你使用小写字母而不是大写字母,你会做错误的事情:

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ẞ στιγμας στιγμασ στιγμας Στιγμας ΣΤΙΓΜΑΣ ᾲ στο διάολο ὰι στο διάολο ᾲ στο διάολο Ὰͅ Στο Διάολο ᾺΙ ΣΤΟ ΔΙΆΟΛΟ

是的,我知道 stigma 的复数是 stigmata 而不是 stigmas;我试图展示最终的西格玛问题。 ς 和 σ 都是大写西格玛 Σ 的有效小写版本。如果你“只存储小写字母”,那么你会得到错误的结果。

如果您使用 Java 的

Pattern

 类,则必须同时指定 
CASE_INSENSITIVE
UNICODE_CASE
,但您仍然无法获得正确的结果,因为虽然 Java 使用完整的大小写映射,但它仅使用简单的大小写折叠。 
这是一个问题。

至于突厥语,是的,突厥语确实有一个特殊的情况。例如,

stanbul 的突厥语折页只是 ı̇stanbul,而不是您应该得到的 i̇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"

如果您正在编写回归测试套件,这里还有更多表行:

[ "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,就像我在上面的早期表格中所做的那样。再次注意最后一行的大小写与小写不同。


1
投票
为 toLowerCase() 指定区域设置,而不是使用系统默认值。这可以防止系统区域设置发生更改。

至于Java未来版本中可能发生的unicode变化,我认为不值得编写代码来处理这个问题。记录产品支持 Java 6,然后转向客户真正想要的功能。


0
投票
我认为最长远的解决方案是

    将当前默认语言环境和技术堆栈版本(在我的例子中是Java版本)记录到配置中
  • 如果它发生了变化(自上次启动以来,或运行区域设置 - 取决于所述技术堆栈如何加载),则锁定存储并重新索引所有受影响的数据集。
显然,这需要发生在主接口级别;如果我在 java 中进行这些更改,我最好希望它是我唯一的数据接口机制(例如,其他技术人员不会查询底层表存储)

© www.soinside.com 2019 - 2024. All rights reserved.