https://www.acmicpc.net/problem/13989
문제 개요
Abbreviation은 약어, 약자라는 뜻으로 두문자어를 나타낼 때 흔히 많이 쓴다. FCM (Firebase Cloud Messaging), GNU (GNU is Not Unix) 등등..
주어진 문장에서 Abbreviation을 뽑아내서 약어 (원문) 형식으로 나타내는 게 요점이다. 단, Abbreviation은 오직 첫 글자가 대문자이고 그 뒤로는 전부 소문자인 패턴이 반복되어야지만 성립한다. 때문에 Make. Korea. Great. Again 같은 건 안 된다. Abcde ABcde 같은 것도 안 된다.
해결 과정
우선 대충 짐작했던 대로 정규표현식을 사용하여 해결할 수 있는 문제다. 자바스크립트에는 String.prototype.replaceAll()
이 있어서 표준 입력을 받고 replaceAll() 한 번 해주면 끝난다. 문제는 정규식을 짜는 과정이다.
우선 첫 글자가 대문자이고 그 뒤로는 전부 소문자여야 하기 때문에 ([A-Z][a-z]+)
식으로 일차적인 부분을 작성해볼 수 있다. 이렇게 하면 Abcdefg 같은 패턴을 인식한다.
그런데 문제 조건에서도 알 수 있듯이 Make. Korea. Great. Again 같은 건 안 된다. 따라서 이 파트가 종료되고 뒤에 오는 건 무조건 띄어쓰기여야 한다. 그리고 이게 적어도 2회 이상 반복되어야 Abbreviation이라고 할 수 있다. 그럼 한 덩어리로는 ([A-Z][a-z]+ )+
정도를 생각해볼 수 있다.
+는 1회 이상 반복되는 걸 의미하기 때문에 대신 {2,}
를 적어야 하지 않나 싶을 수도 있지만, 그렇게 하면 뒤에 띄어쓰기 때문에 패턴 매칭이 불가능하다. 대신, 그 뒤에도 똑같은 조건을 가진 문자열이 한 번’만’ 와야 하기 때문에 (([A-Z][a-z]+ )+([A-Z][a-z]+))
정도가 답이 되겠다.

그렇게 제출하면 정답이라는 문구를 볼 수 있다.

라고 생각하면서 이 정규식을 그대로 긁어다 제출했다면 축하한다. 틀렸다.
이 정규식만으로는 ABc Abcde AbC가 Abbreviation 처리되는 문제를 해결할 수 없다. 문장 전체에서 나타나는 부분을 잡아야 하므로 ^$를 쓸 수 없는데, 이 때문에 ABc Abcde AbC가 잡혀버리기 때문이다. 그럼 어떻게 해야 이 문자열에 반응하지 않도록 정규식을 짤 수 있을까?

정규식에는 \b
라는 메타 문자열이 있다. 이게 뭐 하는 거냐면, Word Boundary에 대한 매칭용이다. A quick brown fox jumps over the lazy dog.
라는 문자열이 있다면, 여기에 대한 \b
는 “단어와 단어가 아닌 문자열의 사이”에 각각 매칭된다. 다시 말해 \w
와 \W
사이에 매칭된다. \w
는 [a-zA-Z0-9]
와 동일하므로 문자열 맨 끝의 dot에는 매칭되지 않는다.
이 문제에 필요한 메타 문자열이 바로 이것이다. ABc Abcde AbC라는 문자열을 단어 단위로 끊으면 ABc, Abcde, AbC가 되므로, 여기에 \b
를 적용하면 당연히 매칭이 안 될 것이다. 따라서 정답은 /\b(([A-Z][a-z]+ )+([A-Z][a-z]+))\b/g
가 되겠다.
const input = require('fs').readFileSync(0, 'utf8').trim();
const regex = /\b(([A-Z][a-z]+ )+([A-Z][a-z]+))\b/g;
const replaced = input.replaceAll(regex, (s) => `${s.split(' ').map((e) => e[0]).join('')} (${s})`);
console.log(replaced);

진짜로 맞았다.