fix: EgovEscapableDelimitedLineTokenizer 가 정규식 메타문자 구분자를 이스케이프하지 못하는 문제 수정 - #367
Merged
jei007 merged 1 commit intoSep 10, 2026
Merged
Conversation
…문제 수정
getRegexDelimiter() 는 delimiter 를 String.split() 의 정규식으로 넘기기 전에
메타문자를 이스케이프하는 자리인데, 괄호류 일곱 문자만 역슬래시가 붙은 형태를
찾는다. replace() 의 첫 인자는 리터럴이라 "\\(" 는 두 글자 \( 를 뜻하고,
구분자로 흔히 쓰는 홑문자 ( 는 아무 처리 없이 통과한다.
그 결과 doTokenize() 의 line.split(regexDelimiter, -1) 에서
( ) { [ 는 PatternSyntaxException 으로 배치가 멈추고,
^ 는 행 처음에만 맞는 앵커로 해석돼 예외 없이 컬럼이 하나로 붙는다.
같은 패키지의 EgovDelimitedLineTokenizer 는 indexOf() 로 나누므로
같은 구분자를 정상 처리하고, 곧이어 오는 * + $ | 네 줄도 홑문자를 받는다.
replace() 의 대상을 홑문자로 바꿔 일곱 문자 모두 이스케이프되게 했다.
역슬래시가 붙은 입력만 찾던 기존 조건은 실제로 맞는 입력이 없었고,
맞더라도 \\( 라는 깨진 정규식이 되므로 잃는 동작은 없다.
jei007
approved these changes
Sep 10, 2026
jei007
left a comment
Contributor
There was a problem hiding this comment.
표준프레임워크에 대한 지속적인 참여에
대단히 감사드립니다.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
수정 사유 Reason for modification
수정된 소스 내용 Modified source
EgovEscapableDelimitedLineTokenizer.getRegexDelimiter()가 정규식 메타문자 구분자를 이스케이프하지 못합니다.이 메서드는 delimiter 를
String.split()의 정규식으로 넘기기 전에 메타문자를 처리하는 자리입니다(EgovEscapableDelimitedLineTokenizer.java:101의// regex 정규식에서 특수문자로 인식하는 것에 대한 처리). 그런데 205~211행 일곱 줄은 역슬래시가 붙은 두 글자를 찾습니다.replace()의 첫 인자는 리터럴이라"\\("는\와(두 글자를 뜻합니다. 구분자로 쓰는 홑문자(는 어디에도 걸리지 않고 그대로 통과합니다.그 결과 140행
line.split(this.regexDelimiter, -1)에서(){[는PatternSyntaxException으로 배치가 멈추고,^는 행 처음에만 맞는 앵커로 해석되어 예외 없이 세 컬럼이 하나로 붙습니다.이 클래스가 delimiter 를 정규식이 아니라 리터럴로 다룬다는 근거는
doTokenize()안에 있습니다. 따옴표로 묶인 셀을 다시 이어붙일 때 원본 delimiter 를 그대로 끼워넣으므로, 정규식으로 받는 계약이라면 재조립된 토큰에 정규식 문자열이 섞여 나옵니다.같은 패키지의
EgovDelimitedLineTokenizer는 정규식을 쓰지 않아 같은 구분자를 그대로 처리합니다.getRegexDelimiter()에서 이어지는 네 줄은 홑문자를 받습니다.일곱 줄이 갈린 지점은 커밋
6b5529d입니다. 이 커밋 전에는 같은 일곱 줄이replaceAll이었고,replaceAll의 첫 인자는 정규식이라"\\("가 홑문자(에 매치했습니다..\?는 그 이전 구현에도 없어서 이 diff 에 없습니다. 이 세 문자는 회귀가 아닙니다.AS-IS / TO-BE
6b5529d이전으로 되돌리는 대신replace를 둔 채 찾는 대상만 홑문자로 바꿨습니다. 이 메서드에 남아 있던replaceAll은69e822a가$구분자에서 나던IllegalArgumentException을 없애려고 걷어낸 것이라, 되돌리면 그 수정을 무르는 셈입니다. 홑문자 입력에 대한 결과 문자열은6b5529d이전과 같습니다.private String getRegexDelimiter(String delimiter) { - delimiter = delimiter.replace("\\(", "\\\\("); - delimiter = delimiter.replace("\\)", "\\\\)"); - delimiter = delimiter.replace("\\{", "\\\\{"); - delimiter = delimiter.replace("\\}", "\\\\}"); - delimiter = delimiter.replace("\\^", "\\\\^"); - delimiter = delimiter.replace("\\[", "\\\\["); - delimiter = delimiter.replace("\\]", "\\\\]"); + delimiter = delimiter.replace("(", "\\("); + delimiter = delimiter.replace(")", "\\)"); + delimiter = delimiter.replace("{", "\\{"); + delimiter = delimiter.replace("}", "\\}"); + delimiter = delimiter.replace("^", "\\^"); + delimiter = delimiter.replace("[", "\\["); + delimiter = delimiter.replace("]", "\\]"); delimiter = delimiter.replace("*", "[*]");범위를 일곱 줄로 잡은 이유
일곱 문자를 문자별로 확인한 결과입니다.
}와]는 Java 정규식이 짝 없는 닫는 문자를 리터럴로 받아주어 origin/main 에서도 나뉩니다. 그래도 함께 되돌린 것은6b5529d가 일곱 줄을 한 묶음으로 바꿨기 때문입니다. 동작하는 두 줄은 건드리지 않는 편이 낫다고 보시면( ) { [ ^다섯 줄로 줄이겠습니다.Pattern.quote()로 메타문자를 한꺼번에 덮는 방법이 있지만* + $ |가 만드는 출력 문자열까지 바뀌므로 회귀 수정과 섞지 않았습니다. 필요하시면 별건으로 올리겠습니다.영향 범위
바뀌는 것은 구분자에
( ) { } ^ [ ]가 들어올 때getRegexDelimiter()가 돌려주는 문자열입니다.역슬래시를 붙여
\(를 넣던 입력은 전후가 같습니다. 수정 전에는\(가\\(가 되고, 수정 후에는\가 그대로 남고(만\(가 되어 역시\\(입니다. 나머지 여섯 문자도 같은 식입니다.저장소 안에서 이 클래스를 쓰는 자리는 테스트 잡 설정 하나와 기존 테스트 클래스 셋입니다. 거기서 주는 구분자는 콤마(기본 생성자 포함)와
$,|이고, 셋 다 바뀐 일곱 줄에 걸리지 않습니다.JUnit 테스트 JUnit tests
EgovEscapableDelimitedLineTokenizerMetaCharTest를 더했습니다. 일곱 문자를 차례로 구분자로 주어a<구분자>b<구분자>c가 세 컬럼으로 나뉘는지, 그리고 같은 입력에 대한EgovDelimitedLineTokenizer결과와 일치하는지 확인합니다.이 저장소는 워크플로 트리거가
contribution브랜치라base=mainPR 에는 CI 가 붙지 않습니다. 실행 출력을 옮깁니다. 디버그 로그 줄은 앞머리(타임스탬프·레벨·로거 이름·### 클래스명)를 잘라냈습니다.수정 전입니다. 일곱 줄만 origin/main 상태로 되돌렸고, 되돌린 파일이 origin/main 과 바이트 동일함을
git diff origin/main -- Batch/org.egovframe.rte.bat.core/src/main/java/org/egovframe/rte/bat/core/item/file/transform/EgovEscapableDelimitedLineTokenizer.java가 빈 출력인 것으로 확인했습니다.로그의
getRegexDelimiter() : (가 이스케이프되지 않은 채 정규식으로 나간 값입니다. 첫 문자에서 던지므로 뒤의 여섯 문자는 이 실행에서 드러나지 않습니다.^는 예외를 던지지 않아 따로 확인했습니다. 일곱 줄 중^한 줄만 origin/main 상태로 두면 이렇게 나옵니다.수정 후입니다. 일곱 문자가 모두 이스케이프되어 나갑니다.
모듈 전체입니다.
테스트 브라우저 Test Browser
테스트 스크린샷 또는 캡처 영상 Test screenshots or captured video
화면이 없는 실행환경 모듈이라 첨부하지 않았습니다.