본문 바로가기
메이킹 로그와 트러블슈팅

[텍스트 차이점 비교기 메이킹 로그 #04] 공백 하나 때문에 코드 전체가 바뀌었다고? 정규식을 활용한 텍스트 비교 엣지 케이스(Edge Case) 정복기

by 코드메이트 2026. 4. 27.

안녕하세요! 코드브릭스(Code-Bricks)의 다양한 생산성 도구들을 열심히 개발하고 있는 프론트엔드 개발자입니다.

드디어 텍스트 차이점 분석기(Diff Checker) 개발기의 마지막 이야기인 [트러블슈팅 2편]을 들고 돌아왔습니다! 지난 3편에서 브라우저를 뻗게 만들던 대용량 텍스트 렌더링 지연(Freezing) 문제를 Web Worker와 Virtual Scroll의 조합으로 멋지게 해결했던 눈물겨운 사투, 잘 보셨나요? (※ 아, 이 모든 고생의 결정체인 실제 차이점 분석기 사이트 링크는 추후 본문 하단에 업데이트할 예정이니, 잊지 말고 꼬옥! 다시 놀러 와주세요!)

성능까지 최적화하고 나서 "이제 진짜 런칭이다!"라고 생각하며, 제가 평소에 작업하던 자바스크립트 코드 파일 두 개를 복사해서 분석기에 딱 붙여넣었습니다. 그런데... 어라?

분명히 코드 내용은 100% 똑같은데, 분석기 결과 화면 전체가 새빨갛게(삭제) 변하더니, 다시 새파랗게(추가) 변하는 대참사가 벌어졌습니다. "공백(Space) 하나, 줄바꿈(Enter) 하나 때문에 이 수백 줄의 코드가 전부 다른 코드로 인식되었다고?"

오늘은 이 황당하고도 절망적인 상황을 정규 표현식(Regex)이라는 강력한 무기로 어떻게 극복했는지, 프론트엔드 텍스트 처리의 숨은 복병인 '엣지 케이스(Edge Case) 정복기'를 들려드리겠습니다.

 

1. 보이지 않는 적, 공백과 줄바꿈의 습격 (이슈 발생)

텍스트 비교기(Diff Checker)의 생명은 정확성입니다. A라는 문서를 B라는 문서로 복사해 붙여넣었을 때, 사람이 보기에 똑같다면 컴퓨터도 똑같다고 인식해야 합니다. 그런데 사용자가 윈도우(Windows) 메모장에서 쓴 글을 복사해서 분석기에 넣고, 맥북(Mac) 사용자가 수정한 글을 복사해서 넣었더니, 내용이 완벽하게 일치함에도 불구하고 LCS 알고리즘은 "이 두 문서는 100% 다른 문서입니다"라는 충격적인 결론을 내버렸습니다.

이유를 파기 위해 콘솔(Console) 창을 열어 문자열의 원시 데이터(Raw Data)를 뜯어보았습니다. 범인은 바로 눈에 보이지 않는 유령 같은 존재들, '줄바꿈 문자(Newline Characters)'와 '후행 공백(Trailing Spaces)'이었습니다.

 

줄바꿈 문자 차이 Carriage Return Line Feed 엣지 케이스 텍스트 비교 오작동

 

2. OS(운영체제)마다 다른 엔터(Enter)의 비밀 (원인 분석)

우리가 무심코 치는 키보드의 엔터(Enter) 키는 화면상에서는 똑같이 줄을 바꿔주지만, 컴퓨터가 인식하는 기계어로는 운영체제에 따라 완전히 다르게 저장됩니다.

  • Windows 환경: \r\n (Carriage Return + Line Feed) - 커서를 맨 앞으로 보내고 줄을 바꿈.
  • macOS / Linux 환경: \n (Line Feed) - 그냥 줄만 바꿈.

윈도우에서 작성한 hello\r\nworld와 맥에서 작성한 hello\nworld는 사람 눈에는 둘 다 두 줄짜리 "hello world"로 보입니다. 하지만 문자열을 엄격하게 바이트(Byte) 단위로 비교하는 LCS 알고리즘의 눈에는, \r이라는 문자가 하나 더 들어간 윈도우 텍스트를 "완전히 다른 단어!"라고 판정해 버리는 대참사가 일어나는 것이죠.

뿐만 아니라, 사용자들이 문장을 쓰다가 무심코 스페이스바를 한두 번 더 누른 뒤 저장하는 경우(Trailing Spaces), 혹은 들여쓰기(Indentation)를 탭(Tab, \t)으로 했느냐 스페이스(Space) 4번으로 했느냐에 따라서도 수많은 오작동이 쏟아져 나왔습니다.

알고리즘이 똑똑한 게 아니라 너무 고지식(?)해서 생긴 문제, 우리는 이것을 '엣지 케이스(Edge Case)'라고 부릅니다. 이 고지식한 알고리즘에게 텍스트를 넘겨주기 전에, 사람이 보기에 똑같은 건 똑같다고 우길 수 있도록 '데이터 세탁'을 거쳐야만 했습니다.

 

3. 정규 표현식(Regex)을 활용한 텍스트 전처리 (해결 액션)

이 엣지 케이스들을 하나하나 조건문(if...else)으로 잡아내는 건 불가능에 가깝습니다. 그래서 저는 텍스트 처리의 마법 지팡이인 '정규 표현식(Regular Expression)'을 꺼내 들었습니다. 비교 연산을 시작하기 전, 사용자가 입력한 두 텍스트(원본/수정본)를 아주 깨끗하게 정제(Sanitization)하는 '전처리 파이프라인'을 구축한 것이죠.

// 텍스트 비교 전 엣지 케이스를 없애기 위한 정규식 전처리 로직 (의사 코드)
function sanitizeTextForDiff(rawText) {
    let sanitizedText = rawText;

    // 1. 모든 종류의 줄바꿈(\r\n, \r)을 Unix 스타일의 표준 줄바꿈(\n)으로 통일
    sanitizedText = sanitizedText.replace(/\r\n|\r/g, '\n');

    // 2. 문장 맨 끝에 붙어있는 쓸데없는 보이지 않는 공백들(Trailing Spaces) 제거
    // (보통 코드 끝이나 문단 끝에 스페이스바를 실수로 누른 경우)
    sanitizedText = sanitizedText.replace(/[ \t]+$/gm, '');

    // 3. (선택적 옵션 기능) 연속된 다중 공백을 하나의 공백으로 취급할 것인가?
    // 이건 사용자 옵션으로 두는 것이 좋습니다. 코드의 들여쓰기는 중요하기 때문이죠.
    // sanitizedText = sanitizedText.replace(/ +/g, ' '); 

    return sanitizedText;
}

이 간단한 정규식 파이프라인 몇 줄을 거치자 기적 같은 일이 일어났습니다! 윈도우 코드와 맥 코드를 붙여넣어도 오직 '사람 눈에 보이는 글자'가 바뀌었을 때만 빨간색(-)과 초록색(+) 하이라이팅이 정확하게 꽂히기 시작했습니다. 눈에 보이지 않는 공백 하나 때문에 문서 전체가 수정되었다고 시뻘겋게 칠해지던 공포가 완전히 사라진 것이죠.

 

정규표현식 Regex 텍스트 전처리 데이터 정제 후행 공백 제거 프론트엔드 예외 처리

 

4. 끝나지 않은 고민: 줄(Line) 단위 vs 단어(Word) 단위

엣지 케이스를 정복하고 나니, 또 다른 깊은 고민(딜레마)에 빠졌습니다. 개발자들이 코드를 볼 때는 '줄(Line)' 단위로 어디가 추가되고 삭제되었는지 보는 것이 편합니다. 하지만 만약 작가님이나 편집자가 300글자짜리 긴 문단을 한 줄로 이어서 썼는데, 그중 딱 "그리고"라는 세 글자만 "그래서"로 바뀌었다면 어떨까요?

지금의 로직은 줄 단위 비교이므로, 그 거대한 문단 한 줄 전체가 삭제(-)되고 통째로 새로 추가(+)되었다고 시뻘겋게 칠해버립니다. 사용자는 "대체 이 긴 문단에서 뭘 고친 거야?" 하고 다시 매직아이에 빠지게 되겠죠.

그래서 코드브릭스의 차이점 분석기는 현재의 '줄(Line) 단위' 거시적 비교를 넘어서, 줄 안에서도 정확히 어떤 단어(Word)가 바뀌었는지 더 진한 색상으로 세밀하게 칠해주는 '글자(Char)/단어 단위 미세 하이라이팅' 기능을 향후 로드맵의 1순위로 올려두었습니다. (조금만 더 기다려 주세요! 지금도 열심히 머리를 쥐어뜯으며 LCS 알고리즘을 2중으로 돌리는 연구를 하고 있답니다.)

 

5. 4부작을 마무리하며

어떠셨나요? 텍스트를 그저 나란히 놓고 비교하는 것처럼 보이는 이 심플한 웹사이트 하나를 만들기 위해, 클라이언트 아키텍처 설계, 무거운 LCS 알고리즘 연산 최적화(Web Worker), DOM 렌더링 버벅거림 방지(Virtual Scroll), 그리고 오늘 다룬 OS별 텍스트 엣지 케이스 전처리(Regex)까지 참 많은 프론트엔드의 땀방울이 녹아들어 갔습니다.

단순한 토이 프로젝트였지만 이 과정에서 얻은 깊이 있는 성능 최적화와 예외 처리 경험은 프론트엔드 개발자로서 제 성장에 엄청난 자양분이 되었습니다.

앞으로 오픈될 코드브릭스(Code-Bricks)의 텍스트 차이점 분석기(Diff Checker)가 개발자들의 코드 리뷰는 물론, 수많은 법무팀, 기획자, 작가님들의 야근 시간을 단 1분이라도 줄여줄 수 있기를 진심으로 바랍니다. 완성된 링크는 추후 본 포스팅 하단에 업데이트될 예정이니 꼭 북마크 해두시고 방문해 주세요!

지금까지 긴 메이킹 로그 4부작을 함께 읽어주셔서 진심으로 감사합니다. 오늘도 즐겁고 버그 없는 코딩 하세요!