문장에서 따옴표(quotes) 안에 들어간 부분을 얻기 위한 정규식(Regular Expression)을 만들기 위해 ChatGPT를 이용했습니다.
다음과 같은 간단한 문장일 경우
This is "a 'sample' string" with 'quotes "in" it'.
바라는 결과
a 'sample' string
quotes "in" it
ChatGPT에서는 다음 정규식을 쓸 수 있다고 답했습니다.
/"([^"]*)"|'([^']*)'/g
/(['"])(.*?)\1/g
그러나 다음 문장과 같이 `따옴표 안에 이스케이프 된 따옴표`가 들어간 경우 위 정규식은 엉뚱한 결과가 나옵니다. (밑에 있는 코드 테스트에서 볼 수 있습니다.)
This is "a \\"sample\\" \\string" with 'quotes "in" it'.
바라는 결과:
a "sample" string
quotes "in" it
그래서 ChatGPT에서 다시 물어봐서 다음과 같은 정규식을 얻었습니다.
/(['"])((?:\\.|(?:(?!\1)[^\\]))*)\1/g
다음과 같이 해도 똑같습니다.
/(['"])((?:\\.|(?!\1)[^\\])*)\1/g
/(['"])((?:\\.|[^\\])*?)\1/g
/(['"])((?:\\.|(?:(?!\1).))*)\1/g
/(['"])((?:\\.|(?:[^\1]))*?)\1/g
이 정규식들에 대한 설명은 아래 대화 내용에서 볼 수 있습니다.
또한 코드 결과를 확인해 보고 테스트해 볼 수 있도록 codepen 프레임을 그 밑에 넣었습니다.
ChatGPT와 대화
javasript에서 regular expression으로 큰따옴표와 작은따옴표를 구별 없이 쓰인 문장 가운데 따옴표로 둘러싸인 부분을 얻는 코드는?
JavaScript에서 정규 표현식을 사용하여 큰따옴표나 작은따옴표를 구별하지 않고 따옴표로 둘러싸인 부분을 추출하는 방법은 다음과 같습니다.
const text = 'This is a "sample" string with \'quotes\' in it.';
const regex = /(['"])(.*?)\1/g;
let match;
while ((match = regex.exec(text)) !== null) {
const word = match[2];
console.log(word);
}
실행 결과:
sample
quotes
위 코드는 `text` 문자열에서 정규 표현식 `regex`를 사용하여 모든 따옴표로 둘러싸인 단어를 추출합니다. `regex`는 다음과 같은 패턴으로 구성됩니다.
- `(['"])`: 따옴표를 나타내는 캡처 그룹입니다. `['"]`는 큰따옴표나 작은따옴표를 나타냅니다. 캡처 그룹을 사용하면 추후에 `match[1]`로 따옴표 종류를 참조할 수 있습니다.
- `(.*?)`: 따옴표로 둘러싸인 문자열을 나타내는 캡처 그룹입니다. `.*?`는 가능한 한 최소한의 문자를 일치시키기 위해 사용됩니다.
- `\1`: 앞서 캡처한 따옴표와 일치하는 백슬래시 그룹 참조입니다.
while 루프는 모든 일치 항목을 반복하며, 각 일치 항목의 캡처 그룹 2에 해당하는 문자열을 `word` 변수에 할당합니다. 추출된 단어는 `console.log`를 사용하여 출력할 수 있습니다.
'This is a "sample \"string\"" with \'quotes\' in it.' 같이 큰따옴표 안에 이스케이프 큰따옴표가 있는 경우는?
주어진 문자열 `'This is a "sample \\"string\\"" with \'quotes\' in it.'`은 큰따옴표 안에 큰따옴표가 포함된 문자열입니다. 위에서 제공한 코드에서는 이스케이프 문자열을 고려하여 따옴표로 둘러싸인 부분을 추출하지만, 큰따옴표 안에 큰따옴표가 포함된 문자열을 처리하는 것은 더 복잡합니다.
다음은 이러한 문자열에서 따옴표로 둘러싸인 부분을 추출하는 코드입니다. 이 코드에서는 큰따옴표 안에 큰따옴표가 포함된 문자열을 처리하기 위해 `(?:(?!\1)[^\\])`을 사용하여 일치하지 않는 문자열을 일치시키도록 합니다.
const text = 'This is a "sample \\"string\\"" with \'quotes\' in it.';
const regex = /(['"])(?:\\.|(?:(?!\1)[^\\]))*\1/g;
let match;
while ((match = regex.exec(text)) !== null) {
const word = match[0];
console.log(word);
}
실행 결과:
"sample \"string\""
'quotes'
위 코드는 `text` 문자열에서 정규 표현식 `regex`를 사용하여 모든 따옴표로 둘러싸인 단어를 추출합니다. `regex`는 다음과 같은 패턴으로 구성됩니다.
- `(['"])`: 따옴표를 나타내는 캡처 그룹입니다. `['"]`는 큰따옴표나 작은따옴표를 나타냅니다.
- `(?:\\.|(?:(?!\1)[^\\]))*`: 따옴표로 둘러싸인 문자열을 나타내는 비캡처 그룹입니다. `(?:...)`는 캡처하지 않는 그룹입니다. `\\.|(?:(?!\1)[^\\])`는 이스케이프 문자열인 `\`와 따옴표가 아닌 모든 문자를 일치시킵니다. `(?!\1)`는 앞서 캡처한 따옴표와 일치하지 않는 문자열을 나타냅니다.
- `\1`: 앞서 캡처한 따옴표와 일치하는 백슬래시 그룹 참조입니다.
while 루프는 모든 일치 항목을 반복하며, 각 일치 항목의 전체 문자열을 `word` 변수에 할당합니다. 추출된 단어는 `console.log`를 사용하여 출력할 수 있습니다.
코드 테스트
"Run"을 누르면 결과를 볼 수 있습니다. 코드를 고쳐서 해 보기 바랍니다.
다음에서는 `따옴표 안에 이스케이프 된 따옴표`가 들어간 경우 a, b와 c, d, e, f 정규식은 다른 결과를 내놓는 것을 확인할 수 있습니다.