Java에서 한글을 정규표현식으로 찾기

문서를 읽어서 한글을 제외한 나머지 문자를 제거하기 위해 정규표현식을 사용했다. 이 과정에서 이해할 수 없는 경험들을 하게 되어 이곳에 정리한다.

처음에는  [^가-힣ㄱ-ㅎㅏ-ㅣ]  형태로 한글을 범위로 해서 찾았는데, 이렇게 하니 윈도우 기반 로컬 머신에서는 잘 동작하던 모듈이 linux 머신에서는 동작하지 않았다. 다른점을 살펴보니 linux 머신은 utf-8 기반이였고, 한글 정규표현식이 다르게 동작하는 것으로 보였다.

그래서 현재는 [^\\u3131-\\u318E\\uAC00-\\uD7A3] 와 같이 유니코드로 범위를 표시해서 한글 이외의 문자를 제거하고 있다. Java가 내부적으로 UTF-16을 사용하는 것으로 알고 있는데 정규표현식에서 서로 다르게 동작할 수 있다는 사실을 처음 알게 됐고, 이렇게 해결하긴 했지만 동작 원리를 정확히 이해하지는 못하고 있다.

(?u)[^가-힣ㄱ-ㅎㅏ-ㅣ] 이렇게 유티코드 옵션을 주고 실행해도 정상 동작하지 않는다. 찾아보니 UNICODE_CASE 일 때 범위 표현은 사용할 수 없다고 한다.

또 하나 고민은 (</?[bB][rR][ ]*/?>|</?[pP]/?>|</?[dD][iI][vV]/?>|</?[lL][iI]/?>|</?[tT][dD]/?>) 와 같은 형태로 html 태그 중에서 단락을 구분지어 주는 태그를 약속된 구분자로 치환하려는데 이때 2가지 문제가 발생한다.

첫번째는 분석하려는 본문이 길 때 치환에 시간이 많이 걸린다는 것이고, 또 하나는 가끔 StackOverflowError가 발생한다. 검색을 해보니 복잡한 정규표현식이나 분석하려는 대상이 길 때 발생할 수 있고 해결되지 않은 문제라고 한다. 정규표현식을 좀 더 명확하고 단순하게  개선하면 에러 발생을 줄일 수 있다는데 어떻게 하면 될까?

우선은 (?i)(</?br */?>|</?p/?>|</?div/?>|</?li/?>|</?td/?>) 대소문자 구분을 하지 않게 하고 필요 없는 표현을 제거했다. 실행 속도는 거의 변화가 없고 StackOverflowError가 줄어들지는 지켜봐야 한다.

(회사 동료분의 힌트로 다시 한번 수정. 현재는 (?i)</?(br *|p|div|li|td)/?> 형태로 더 간단해졌다.)

This entry was posted in Java and tagged , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>