2011-04-17 94 views
69

下面的代碼是非常熟知的重音字符轉換爲純文本:正則表達式:什麼是InCombiningDiacriticalMarks?

Normalizer.normalize(text, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", ""); 

我通過這一個取代我的「手工製作」的方法,但是我需要了解的的replaceAll

的「正則表達式」的一部分

1)什麼是「InCombiningDiacriticalMarks」?
2)它的文檔在哪裏? (和similars?)

謝謝。

+0

另請參見http://stackoverflow.com/a/29111105/32453顯然,unicode中有更多「組合標記」,而不僅僅是變音符號,就像一個音符一樣。 – rogerdpack 2015-03-18 21:42:42

回答

59

\p{InCombiningDiacriticalMarks}是一個Unicode塊屬性。在JDK7中,您可以使用兩部分表示法\p{Block=CombiningDiacriticalMarks}來編寫它,這對讀者而言可能更加清晰。它記錄在here in UAX#44: 「The Unicode Character Database」

這是什麼意思是代碼點落在一個特定的範圍,一個塊,已被分配用於該名稱的事情。這是一種不好的方法,因爲不能保證該範圍內的代碼點是或不是特定的東西,也不能保證該塊外的代碼點本質上不是相同的字符。

例如,在\p{Latin_1_Supplement}塊中有拉丁字母,如é,U + 00E9。但是,有些東西是而非拉丁字母。當然,還有拉丁字母到處都是。

塊幾乎不是你想要的。

在這種情況下,我懷疑你可能想要使用屬性\p{Mn},也叫做\p{Nonspacing_Mark}。 Combining_Diacriticals塊中的所有代碼點都屬於這種類型。還有(來自Unicode 6.0.0)1087 Nonspacing_Marks,該塊中的而不是

這與檢查\p{Bidi_Class=Nonspacing_Mark}幾乎相同,但不完全相同,因爲該組還包含封閉標記\p{Me}。如果你想要兩者,如果你使用默認的Java正則表達式引擎,你可以說[\p{Mn}\p{Me}],因爲它只允許訪問General_Category屬性。

你不得不使用JNI來獲得在ICU C++ regex庫谷歌確實要訪問像\p{BC=NSM}的方式,因爲現在只有ICU和Perl給所有 Unicode屬性的訪問。普通的Java正則表達式庫僅支持一些標準的Unicode屬性。在JDK7中雖然有支持Unicode Script propery,這對Block屬性來說是無限可取的。因此,您可以在JDK7中編寫\p{Script=Latin}\p{SC=Latin}或快捷方式\p{Latin}以獲取拉丁腳本中的任何字符。這導致非常通常需要[\p{Latin}\p{Common}\p{Inherited}]

請注意,這將不會刪除您可能認爲所有角色的「重音」標記!有很多它不會這樣做。例如,您不能將Đ設置爲Dø那樣。爲此,您需要將代碼點減少爲符合Unicode歸類表中相同主歸類強度的那些代碼點。

\p{Mn}東西失敗的另一個地方當然包含了像\p{Me}這樣的標記,很明顯,還有\p{Diacritic}這些不是標記的字符。可悲的是,你需要完全的財產支持,這意味着JNI要麼是ICU要麼是Perl。恐怕,Java在Unicode支持方面有很多問題。

哦等等,我看你是葡萄牙人。如果你只是在處理葡萄牙語的文字,你應該沒有任何問題。

但是,我並不想刪除重音符號,我敢打賭,而是希望能夠匹配「不區分重音」的東西,對吧?如果是這樣,那麼你可以使用ICU4J (ICU for Java) collator class這樣做。如果您比較主要優勢,重音符號將不會被計算。我一直這樣做,因爲我經常處理西班牙文本。我有一個例子,說明如果你需要的話,西班牙人就坐在這裏。

+0

所以,我必須假設整個網絡(甚至在這裏)給出的方法不是推薦的「DeAccent」一詞。我爲葡萄牙人做了一個直接的,但看到了這種奇怪的方法(就像你說的,它適用於我的目的,但是我的最後一種方法做到了!)。那麼,是否有更好的「實施良好」的方法能夠覆蓋大多數情況?一個例子會非常好。謝謝你的時間。 – marcolopes 2011-04-18 04:11:56

+1

@Marcolopes:我一直保留數據並使用Unicode歸類算法進行主要強度比較。這樣它只是比較字母,但忽略大小寫和重音標記。它還讓*應該*是相同的字母*是*相同的字母,刪除重音只是一個蒼白和不滿意的近似。另外,如果你可以按照你想要但不需要的方式使用數據,那麼它就更簡潔。 – tchrist 2011-04-19 01:06:35

+0

相當不錯的答案,但有一個問題,我可以在java中使用Normalizer並使用InCombiningDiacriticalMarks但排除一些字符,如ü轉換爲u? – AlexCon 2014-03-24 15:18:11

2

我花了一段時間,但我釣大家都出去了:

Here's regex應包括所有zalgo字符包括那些在「正常」範圍繞過。

([\u0300–\u036F\u1AB0–\u1AFF\u1DC0–\u1DFF\u20D0–\u20FF\uFE20–\uFE2F\u0483-\u0486\u05C7\u0610-\u061A\u0656-\u065F\u0670\u06D6-\u06ED\u0711\u0730-\u073F\u0743-\u074A\u0F18-\u0F19\u0F35\u0F37\u0F72-\u0F73\u0F7A-\u0F81\u0F84\u0e00-\u0eff\uFC5E-\uFC62]) 

希望這可以爲您節省一些時間。