Regex : InCombiningDiacriticalMarks 란 무엇입니까?


86

다음 코드는 악센트 부호가있는 문자를 일반 텍스트로 변환하는 것으로 잘 알려져 있습니다.

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

"손으로 만든"방법을이 방법으로 대체했지만 replaceAll의 "정규식"부분을 이해해야합니다.

1) "InCombiningDiacriticalMarks"는 무엇입니까?
2) 문서는 어디에 있습니까? (그리고 유사?)

감사.


또한 stackoverflow.com/a/29111105/32453을 참조 하십시오. 메모처럼 분음 부호보다 유니 코드에 "결합 표시"가 더 많이 있습니다.
rogerdpack

답변:


74

\p{InCombiningDiacriticalMarks}유니 코드 블록 속성입니다. JDK7에서는 두 부분으로 된 표기법을 사용하여 작성할 \p{Block=CombiningDiacriticalMarks}수 있으며 이는 독자에게 더 명확 할 수 있습니다. 여기 UAX # 44 :“The Unicode Character Database”에 문서화되어 있습니다 .

의미하는 바는 코드 포인트가 해당 이름으로 사물에 사용하도록 할당 된 특정 범위 인 블록에 속한다는 것입니다. 이는 잘못된 접근 방식입니다. 해당 범위의 코드 포인트가 특정 항목인지 아닌지 또는 해당 블록 외부의 코드 포인트가 본질적으로 동일한 문자가 아니라는 보장이 없기 때문입니다.

예를 들어 \p{Latin_1_Supplement}블록에는 é, U + 00E9와 같은 라틴 문자가 있습니다. 그러나 거기에는 라틴 문자 가 아닌 것도 있습니다. 물론 여기 저기에 라틴 문자도 있습니다.

블록은 거의 당신이 원하는 것이 아닙니다.

이 경우 \p{Mn}, 일명 이라는 속성을 사용하고 싶을 것 같습니다 \p{Nonspacing_Mark}. Combining_Diacriticals 블록의 모든 코드 포인트는 이러한 종류입니다. 해당 블록에 없는 1087 Nonspacing_Mark도 있습니다 (유니 코드 6.0.0 기준) .

이는를 확인하는 것과 거의 동일 \p{Bidi_Class=Nonspacing_Mark}하지만 해당 그룹에는 \p{Me}. 둘 다 원한다면 [\p{Mn}\p{Me}]General_Category 속성에 대한 액세스 권한 만 제공하므로 기본 Java 정규식 엔진을 사용하고 있다고 말할 수 있습니다.

당신은 ICU C ++ 정규식 도서관에서 같은 액세스 뭔가 구글이 순서대로 수행하는 방법을 얻을 수 JNI를 사용해야 할 것입니다 \p{BC=NSM}때문에 지금 만 ICU와에 펄주고 액세스 모든 유니 코드 속성. 일반 Java regex 라이브러리는 몇 가지 표준 유니 코드 속성 만 지원합니다. JDK7에서는 Block 속성보다 거의 무한히 선호되는 Unicode Script 속성에 대한 지원 이있을 입니다. 따라서 JDK7에서 \p{Script=Latin}또는 \p{SC=Latin}, 또는 바로 \p{Latin}가기를 작성하여 라틴어 스크립트의 모든 문자를 가져올 수 있습니다. 이것은 매우 일반적으로 필요한 [\p{Latin}\p{Common}\p{Inherited}].

모든 문자에서 "악센트"표시로 생각할 수있는 부분이 제거되지는 않습니다. 이것을 위해하지 않을 많은 것들이 있습니다. 예를 들어 ĐD로 또는 øo 로 변환 할 수 없습니다 . 이를 위해 유니 코드 데이터 정렬 테이블에서 동일한 기본 데이터 정렬 강도와 일치하는 코드 포인트로 코드 포인트를 줄여야합니다.

\p{Mn}일이 실패 하는 또 다른 장소 는 당연히와 같은 마크를 둘러싸는 것입니다 \p{Me}. 그러나 \p{Diacritic}마크가 아닌 문자 도 있습니다 . 슬프게도 이에 대한 완전한 속성 지원이 필요합니다. 즉, ICU 또는 Perl에 대한 JNI를 의미합니다. Java는 유니 코드 지원과 관련하여 많은 문제가 있습니다. 두렵습니다.

아 잠깐, 당신이 포르투갈어 인 것 같네요. 포르투갈어 텍스트 만 다루는 경우에는 전혀 문제가 없을 것입니다.

하지만 악센트를 제거하고 싶지는 않지만 "악센트를 구분하지 않고"일치시킬 수 있기를 원합니다. 그렇다면 ICU4J (Java 용 ICU) collator 클래스를 사용하여 수행 할 수 있습니다 . 기본 강도로 비교하면 악센트 표시가 포함되지 않습니다. 나는 스페인어 텍스트를 자주 처리하기 때문에 항상 이렇게합니다. 필요한 경우 여기 어딘가에 앉아 스페인어를 사용하는 방법에 대한 예가 있습니다.


그래서 나는 웹 전체 (그리고 여기에서도 SO)에서 주어진 방법이 "DeAccent"단어에 대해 권장되는 방법이 아니라고 가정해야합니다. 나는 포르투갈어로만 똑바로 만들었지 만 이상한 접근 방식을 보았습니다 (그리고 당신이 말했듯이 그것은 내 목적을 위해 작동하지만 마지막 방법은 그랬습니다!). 그렇다면 대부분의 시나리오를 포괄하는 더 나은 "잘 구현 된"접근 방식이 있습니까? 예가 매우 좋을 것입니다. 시간 내 줘서 고마워.
marcolopes 2011

1
@Marcolopes : 데이터를 그대로두고 Unicode Collation Algorithm을 사용하여 1 차 강도 비교를 수행했습니다. 이렇게하면 문자 만 비교하지만 대소 문자와 악센트 표시를 모두 무시합니다. 또한 일 수 있어야 같은 문자가 될 악센트를 제거하는 단지 창백하고 불만족스러운 근사 같은 편지를. 또한 원하는 작업을 수행하지만 필요하지 않은 방식으로 작업 할 수 있다면 데이터를 압축하지 않는 것이 더 깨끗합니다.
tchrist 2011

꽤 좋은 대답이지만 한 가지 질문은 Java에서 Normalizer를 사용하고 InCombiningDiacriticalMarks를 사용할 수 있지만 ü와 같은 일부 문자를 u로 변환하지 않을 수 있습니까?
AlexCon 2014 년

6
예, 저는이 모든 것을 완전히 이해했습니다
Dónal 2014 년

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.