3

我正在使用Java的文件名列表。什麼組件處理字符串中的組合Diaieresis?

我觀察到,在文件名中的一些單字符,如A,O和U實際上由一個序列的,你可以爲兩個單ASCII字符跟進描述:

öo表示,¨

我通過與codePointAt()檢查看到這一點。德國名「Rölli」實際上是「Ro¨lli」:

... 
20: R, 82 
21: o, 111 
22: ̈, 776 
23: l, 108 
24: l, 108 
25: i, 105 
... 

上面的日誌中的字符¨value 776,這是一個「組合分音符」。這是一個所謂的組合標記,屬於graphemes,更確切地說是combining diacritics。所以這一切都合情合理,但我不明白什麼軟件組件將這兩個字符組合到一個變音符號中,並指定了這種行爲。

  • 它與強大的字符代碼表使用幾個字節作爲內部表示形式無關。幾個字節與兩個組合字符不同。
  • 字符串的任何簡單print()都顯示了組合字符,所以它既不是上面的某個UI層。
  • 我記得用PHP觀察過。我想任何現代語言都可以處理這個問題。

什麼組件會導致組合字符顯示爲單個組合字符?這一切有多可靠?

Java是一種標準化方法,可以使組合代碼點的單個代碼點,如here?將是使用正則表達式的幫助...

非常感謝任何提示。

回答

3

答1:規範和責任

您所描述的行爲Unicode Standard Annex #15, Unicode Normalization Forms定義。這涉及組合字符和單個代碼點的等價性以及代碼點的分解。德語以外的許多語言嚴重依賴構成字形。

Java在內部將字符串表示爲UTF-16。所以它的String類都會向其他組件提供UTF-16代碼鏈。這取決於周圍的軟件(例如任何類型的文本查看組件)以正確地組合鏈。在瞬間,例如,正則表達式會將您的組合ö分開,但它在某些視圖中正確顯示。順便說一句,如果你用Combining Diaeresis做了一些實驗,請注意,還有一個「非功能性」代碼168,它是一個簡單的ASCII字符,稱爲「Spacing Diaeresis」。代碼168不會導致任何軟件將兩個代碼點合併爲一個。爲此,您需要Unicode 776。

答2:Java類歸一化法

基本上,你應該始終把組合字符考慮 - 除非你確信你的數據源不能救他們。首先清理字符串是個好主意。

尋找使用您的語言的unicode標準化方法,因爲它們釋放您擺脫單個replace()聲明,並且它們包含大量的經驗。

Java有一個Normalizer對象與組合字符的不同表示涉及:

https://docs.oracle.com/javase/7/docs/api/java/text/Normalizer.html

,併爲它的教程:https://docs.oracle.com/javase/tutorial/i18n/text/normalizerapi.html

所以調用此代碼行後:

String normalized = Normalizer.normalize(someFileName, Normalizer.Form.NFC); 

從上面的問題的日誌打印看起來像這樣:

... 
19: , 32 
20: R, 82 
21: ö, 246 <<< here were two combined chars before normalize() 
22: l, 108 
23: l, 108 
24: i, 105 
...