正規表現:InCombiningDiacriticalMarksとは何ですか?


86

次のコードは、アクセント付きの文字をプレーンテキストに変換することでよく知られています。

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

「手作り」の方法をこれに置き換えましたが、replaceAllの「正規表現」の部分を理解する必要があります

1)「InCombiningDiacriticalMarks」とは何ですか?
2)それの文書はどこにありますか?(および類似物?)

ありがとう。


stackoverflow.com/a/29111105/32453も参照してください。メモとして、ユニコードには発音区別符号だけでなく「結合マーク」が多いようです。
rogerdpack 2015年

回答:


74

\p{InCombiningDiacriticalMarks}Unicodeブロックプロパティです。JDK7では、2つの部分からなる表記を使用して記述できるようになります\p{Block=CombiningDiacriticalMarks}。これは、読者にとってより明確な場合があります。これは、UAX#44「Unicode文字データベース」に記載されています。

これは、コードポイントが、その名前で使用するために割り当てられた特定の範囲、つまりブロック内にあることを意味します。これは悪いアプローチです。その範囲内のコードポイントが特定のものであるかどうか、またはそのブロックの外側のコードポイントが本質的に同じ文字ではないという保証がないためです。

たとえば、\p{Latin_1_Supplement}ブロックには、é、U + 00E9などのラテン文字があります。ただし、そこにはラテン文字ではないものもあります。そしてもちろん、至る所にラテン文字もあります。

ブロックはほとんどあなたが望むものではありません。

この場合、プロパティ\p{Mn}、別名を使用することをお勧めします\p{Nonspacing_Mark}。Combining_Diacriticalsブロック内のすべてのコードポイントはそのようなものです。(Unicode 6.0.0以降)そのブロックにない1087Nonspacing_Marksもあります。

これは、のチェックとほぼ同じですが\p{Bidi_Class=Nonspacing_Mark}、そのグループには囲みマークも含まれているため、完全ではありません\p{Me}。両方が必要な[\p{Mn}\p{Me}]場合は、デフォルトのJava正規表現エンジンを使用しているかどうかを判断できます。これは、General_Categoryプロパティへのアクセスのみを提供するためです。

\p{BC=NSM}現在、ICUとPerlのみがすべてのUnicodeプロパティへのアクセスを許可しているため、Googleが行う方法でICU C ++正規表現ライブラリにアクセスするにはJNIを使​​用する必要があります。通常のJava正規表現ライブラリは、いくつかの標準Unicodeプロパティのみをサポートします。JDK7であってもなりますちょうど約無限に好適なブロックプロパティにあるのUnicodeスクリプトproperyをサポートすること。したがって、JDK7で、\p{Script=Latin}または \p{SC=Latin}、またはショートカットを記述\p{Latin}して、ラテン文字から任意の文字を取得できます。これは、非常に一般的に必要とされるつながります[\p{Latin}\p{Common}\p{Inherited}]

すべての文字から「アクセント」マークと思われるものが削除されるわけではないことに注意してください。これを行わないものはたくさんあります。たとえば、ĐDにøoにそのように変換することはできません。そのためには、コードポイントをUnicode照合テーブルの同じプライマリ照合強度に一致するものに減らす必要があります。

\p{Mn}物事が失敗する別の場所は、もちろん\p{Me}、のようなマークを囲むことですが、マーク\p{Diacritic}ではない文字もあります。残念ながら、そのための完全なプロパティサポートが必要です。つまり、JNIからICUまたはPerlへのサポートが必要です。JavaにはUnicodeのサポートに関して多くの問題があります、私は恐れています。

ちょっと待って、あなたはポルトガル人だと思います。ポルトガル語のテキストのみを扱っている場合は、まったく問題はありません。

しかし、あなたは本当にアクセントを削除したくないのではないでしょうか。むしろ、「アクセントに影響されない」ものに一致させたいのですよね?その場合は、ICU4J(ICU for Java)コレータークラスを使用してこれを行うことができます。一次強度で比較すると、アクセント記号はカウントされません。私はスペイン語のテキストを頻繁に処理するため、これを常に行っています。必要に応じて、このあたりに座っているスペイン人のためにこれを行う方法の例があります。


したがって、Web全体(およびここSOでも)で提供されている方法は、「DeAccent」という単語に推奨される方法ではないと想定する必要があります。私はポルトガル語のためだけにストレートなものを作りましたが、この奇妙なアプローチを見ました(そしてあなたが言ったように、それは私の目的のために働きます、しかし私の最後の方法はそうしました!)。それで、ほとんどのシナリオをカバーするより良い「適切に実装された」アプローチはありますか?例はとてもいいでしょう。御時間ありがとうございます。
marcolopes 2011

1
@Marcolopes:データをそのまま残し、Unicode照合アルゴリズムを使用して一次強度の比較を行っています。このようにすると、文字を比較するだけで、大文字と小文字とアクセント記号の両方が無視されます。また、同じ文字である必要があるものを同じ文字することもできます。アクセントを削除することは、淡くて不十分な近似です。さらに、必要なことを実行するがそれを必要としない方法でデータを操作できる場合は、データをザッピングしない方がクリーンです。
tchrist 2011

かなり良い答えですが、1つの質問ですが、Javaでノーマライザーを使用してInCombiningDiacriticalMarksを使用できますが、üなどの一部の文字をuへの変換から除外できますか?
AlexCon 2014年

6
ええ、私は完全にこのすべてを理解
ドナル・

4

しばらく時間がかかりましたが、私はそれらをすべて釣り上げました:

これは、「通常の」範囲でバイパスされたものを含むすべての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])

これで時間を節約できれば幸いです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.