17.12 그룹
지금까지 우리는 문자 단 한 개에 일치하는 것들을 주로 봤습니다.
반복을 사용하며 여러 개를 찾을 수 있지만, 그렇다고 해도 문자 하나를 반복하는 것이었죠.
그룹을 사용하면 하위 표현식을 만들고 단위 하나로 취급할 수 있습니다.
그룹을 사용하면 그 그룹에 일치하는 결과를 나중에 쓸 수 있도록 캡쳐(capture)할 수도 있습니다.
결과를 캡쳐하는 것이 기본값이지만, 캡쳐하지 않는 그룹도 만들 수 있습니다.
필자는 캡쳐하지 않는 그룹부터 설명하려고 합니다.
캡쳐하지 않는 그룹
정규식을 이미 배운 경험이 있다면 캡처하지 않는 그룹부터 설명하는 것이 어색할 수도 있습니다.
하지만 필자는 기본적으로 캡처하지 않는 그룹을 사용하길 권합니다.
캡처하지 않는 그룹을 사용하면 성능상 장점이 있고, 일치하는 결과를 나중에 쓸 필요가 없다면 캡처하지 않는 그룹을 써야 합니다.
그룹은 괄호로 만듭니다.
캡처하지 않는 그룹은 (?:[subexpression]) 형태이고, 여기서 [subexpression]이 일치시키려 하는 패턴입니다.
예제를 봅시다.
도메인 이름을 찾으려 하지만, .com
, .org
, .edu
만 찾는다고 합시다.
const text = "Visit oreilly.com today!";
const match = text.match(/[a-z]+(?:\.com|\.org|\.edu)/i);
그룹에도 반복을 적용할 수 있습니다.
일반적으로 반복은 반복 메타 문자의 바로 왼쪽에 있는 문자 하나에 적용되지만, 그룹을 사용하면 그룹 전체에 반복을 적용합니다.
자주 쓰이는 예제를 봅시다.
htp://, https://, //(프로토콜 독립적 URL)
로 시작하는 URL을 찾으려 한다면 그룹과 함께 0 또는 1개에 일치하는 메타 문자 ?
를 쓰면 됩니다.
const html = '<1ink rel="stylesheet" href="http://insecure.com/stuff.css">\n' +
'<1ink rel="stylesheet" href="https://secure.com/securestuff.css">\n' +
'<1ink rel="stylesheet" href="//anything.com/flexible.css">';
const matches = html.match(/(?:https?)?\/\/[a-z][a-z0-9-]+[a-z0-9]+/ig);
외계어처럼 보이나요?
괜찮습니다.
필자도 그렇게 보이니까요.
하지만 이 예제에는 중요한 내용이 많이 들어 있으므로, 시간을 들여 찬찬히 살펴볼 가치가 있습니다.
정규식 시작에는 캡처하지 않은 그룹 (?:https?)?
가 있습니다.
여기에는 0
또는 1
메타 문자(?
)가 두 개 있습니다.
그중 처음은 ‘s는 옵션이다’라는 뜻입니다.
일반적으로 반복은 반복 메타 문자의 바로 왼쪽에 있는 문자 하나에 적용된다고 했습니다.
두 번째는 그 왼쪽에 있는 그룹 전체에 적용됩니다.
따라서 이 패턴은 빈 문자열, http, https에 일치합니다.
다음에는 이스케이프한 슬래시 두 개 (\/\/
)가 있습니다.
다음에 있는 문자 클래스는 조금 복잡합니다.
도메인 이름에는 글자와 숫자, 하이픈이 들어갈 수 있지만 시작은 글자여야 하고, 하이픈으로 끝날 수는 없습니다.
이 예제는 완벽하지 않습니다.
예를 들어 //gotcha
같은, 최상위 도메인이 없는 URL에도 //valid.com
같은 올바른 URL과 마찬가지로 일치합니다.
하지만 완벽히 유효한 URL에만 일치하는 정규식을 만드는 것은 훨씬 더 복잡한 작업이고 이 예제의 목적에도 맞지 않습니다.
NOTE_
잘못된 URL에도 일치한다는 경고를 하면서 왜 이런 예제를 제시하는지 궁금한가요?
한 번에 모든 일을 다 해치울 필요는 없기 때문입니다.
사실 필자는 웹사이트를 스캔할 때 이와 비슷한 정규식을 사용하곤 합니다.
URL, 또는 URL처럼 보이는 문자열을 모두 찾고 나면 결과를 다시 분석해서 잘못된 URL이나 깨진 URL을 걸러내는 작업을 합니다.모든 경우의 수를 고려하는 완벽한 정규식을 만들겠다는 환상에 빠지지 마십시오.
거의 불가능할 뿐 아니라, 설령 가능하다 해도 불필요한 일입니다.
물론 모든 가능성을 고려해서 시간과 노력을 들여 완벽한 것을 만들어야 할 때도 있습니다.
예를 들어 SQL 주입 공격을 막기 위해 사용자의 입력을 검사하는 정규식을 만든다면 최선을 다해서 정교하게 만들어야 할 겁니다.