프로필사진
김핑9
Ping9
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total

티스토리 뷰

반응형

특정 문자로 시작해서 특정 문자로 끝나는 문장을 찾은 후, 해당 문장에서 일부만 replace 하려고 한다.

평소에 잘 안쓰던 정규식을 쓰려고 하니 과정이 복잡해서 내가 나중에 볼겸 블로그에 저장한다.

(이거보다 쉬운 방법이 있다면 제발 알려주세요... 소스 수정하게...)

 

String originTxt = "HELLO WORLD TEST! <TEST 문자열1> 안녕 < TEST문자열2 > BYE WORLD";
String targetTxt = "HELLO WORLD TEST! <테스트 문자열1> 안녕 < 테스트문자열2 > BYE WORLD";

최종 목표는 위와 같은 텍스트에서 '&lt;'로 시작해서 '&gt;'로 끝나는 문장을 찾은 후, 그 문장 내에서만 일부 내용을 replace하는 것. ('TEST' → '테스트' / '&lt;' → '<' / '&gt;' → '>')

 

가장 먼저 '&lt;'로 시작해서 '&gt;'로 끝나는 문장을 찾기 위해 정규식을 작성했다.

&lt;.*&gt;	// result : "&lt;TEST 문자열1&gt; 안녕 &lt; TEST문자열2 &gt;"

처음에는 이렇게 작성했더니 문자열1 부분과 문자열2 부분을 따로 찾는게 아니라 제일 처음 '&lt;'와 제일 마지막 '&gt;'를 찾아서 문장을 통째로 검색해버렸다.

&lt;.*?&gt;
&lt;(.*?)&gt;	// capturing group
&lt;(?:.*?)&gt;	// non-capturing group

내가 원하는 문장을 찾는 데는 세가지 정규식 모두 먹힌다. (테스트는 여기서 > https://regexr.com/)

처음엔 group을 활용해서 찾은 문장 내에서만 replace할 수 있지 않을까 싶었는데 정규식 숙련도 부족으로 일단 포기.

capturing과 non-capturing의 차이는 match 함수를 사용했을 때 결과배열에 그룹이 포함되냐 안되냐 차이라고 하는데 사실 무슨말인지 100퍼센트 이해하기가 어렵다.

group에 관련된 자세한 내용은 잘 정리해둔 블로그를 참고하자! (blog.rhostem.com/posts/2018-11-11-regex-capture-group)

 

정규식을 통해 문장은 찾았으니 그 문장 내에서만 replace를 해야하는데 어떻게 할까 고민을 하다가

찾은 문장과 그 문장의 앞뒤를 잘라서 따로 저장한 후, 찾은 문장만 replaceAll을 하고 다시 합쳐주는 방식으로 하기로 했다.

마침 Matcher 메소드 중에 찾은 문장의 시작과 끝 인덱스를 리턴해주는 메소드가 있어 이용하였고

replace를 하면 기존 문장과 index가 달라지기 때문에 matcher 함수를 한번 더 호출해서 다시 탐색했다.

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {

    public static void main(String args[]) {
        String originTxt = "HELLO WORLD TEST! &lt;TEST 문자열1&gt; 안녕 &lt; TEST문자열2 &gt; BYE WORLD";
        String targetTxt = "HELLO WORLD TEST! <테스트 문자열1> 안녕 < 테스트문자열2 > BYE WORLD";
        String newTxt = originTxt;
        String reg = "&lt;(?:.*?)&gt;";

        Pattern pattern = Pattern.compile(reg);
        Matcher matcher = pattern.matcher(originTxt);

        while (matcher.find()) {
            System.out.println("Full match: " + matcher.group(0));
            System.out.println("Start index: " + matcher.start(0));
            System.out.println("End index: " + matcher.end(0));

            String matchStr = matcher.group(0);
            String before = newTxt.substring(0, matcher.start(0));
            String after = newTxt.substring(matcher.end(0));
            matchStr = matchStr.replaceAll("&lt;", "<");
            matchStr = matchStr.replaceAll("&gt;", ">");
            matchStr = matchStr.replaceAll("TEST", "테스트");
            newTxt = before + matchStr + after;
            matcher = pattern.matcher(newTxt);

            System.out.println("Change: " + newTxt);
            System.out.println();
        }

        System.out.println("Origin: " + originTxt);
        System.out.println("Result: " + newTxt);
    }
}

 위 코드를 실행해보면 아래와 같은 결과가 나온다.

Full match: &lt;TEST 문자열1&gt;
Start index: 18
End index: 35
Change: HELLO WORLD TEST! <테스트 문자열1> 안녕 &lt; TEST문자열2 &gt; BYE WORLD

Full match: &lt; TEST문자열2 &gt;
Start index: 32
End index: 50
Change: HELLO WORLD TEST! <테스트 문자열1> 안녕 < 테스트문자열2 > BYE WORLD

Origin: HELLO WORLD TEST! &lt;TEST 문자열1&gt; 안녕 &lt; TEST문자열2 &gt; BYE WORLD
Result: HELLO WORLD TEST! <테스트 문자열1> 안녕 < 테스트문자열2 > BYE WORLD

원하는 대로 '&lt;'와 '&gt;' 사이에 있는 'TEST'는 '테스트'로 잘 변경되었고, 그 외의 TEST는 변경되지 않고 그대로이다.

 

나름 시행착오가 많았는데(특히 정규식), 막상 블로그에 포스팅하니 엄청 간단해보여 약간 속상하다.

갈 길이 먼 개발자의 길...

반응형

'공부 > Java' 카테고리의 다른 글

[JAVA] MySQL executeUpdate 사용 시 리턴값  (0) 2018.04.16
댓글