정규식을 읽는 데 필요한 다섯 가지

MIT Missing Semester의 Data Wrangling 강의를 보고 정규식을 정리했습니다. 기호가 붙어 있는 모양만 보면 복잡한데요. 어떤 문자를 찾는지, 몇 번 반복되는지, 어디에 있어야 하는지로 나눠 읽으면 조금 수월합니다.

정규식은 도구마다 문법이 조금씩 다릅니다. 여기서는 JavaScript 정규식을 기준으로 설명하고, 날짜를 치환하는 예제에서는 sed -E를 사용합니다.

어떤 문자를 찾을지

cat은 그대로 cat을 찾습니다. 그런데 gray와 grey를 둘 다 찾고 싶다면 달라지는 자리에 [ae]를 넣어 gr[ae]y로 쓰면 됩니다. [ae]가 a 또는 e 한 글자를 뜻하니 두 단어 모두 찾을 수 있죠.

패턴 찾는 문자
. 줄바꿈을 제외한 문자 하나. s 플래그를 켜면 줄바꿈도 포함
[ae] a 또는 e 하나
[a-z0-9] 영문 소문자나 숫자 하나
[^abc] a, b, c가 아닌 문자 하나
\d 숫자 하나. [0-9]와 같음
\w 기본적으로 영문 대소문자·숫자·밑줄에 해당하는 단어 문자. 한글은 포함하지 않음
\s 공백이나 줄바꿈 같은 공백 문자

몇 번 반복할지

문자 집합이 한 글자의 범위를 정한다면, 수량자는 바로 앞의 문자나 패턴이 반복되는 횟수를 정합니다.

  • ?는 없거나 한 번입니다. colou?r는 color와 colour에 모두 일치합니다.
  • *는 0번 이상, +는 1번 이상입니다.
  • {4}는 정확히 네 번입니다. \d{4}는 네 자리 숫자를 찾습니다.
  • {2,4}는 두 번부터 네 번까지입니다.

반복 횟수만 정하면 될 것 같지만, 어디까지 일치하는지도 봐야 합니다. <b>bold</b>에서 <b>만 찾으려고 <.*>를 쓰면 문자열 전체가 잡히는데요. .*가 첫 번째 >에서 멈추지 않고 마지막 > 앞까지 일치하기 때문입니다. 이렇게 가능한 한 많이 일치시키는 동작을 greedy라고 합니다.

Greedy and lazy matching

<.*>   on <b>bold</b>   →   <b>bold</b>   (greedy)
<.*?>  on <b>bold</b>   →   <b>           (lazy)

수량자 뒤에 ?를 붙이면 가능한 한 적게 일치시킵니다. 그래서 <.*?>는 첫 번째 >에서 멈추고 <b>만 찾습니다.

어디에 있어야 하는지

^와 $는 입력의 시작과 끝을 나타내므로 ^#은 시작 위치의 #을, \.md$는 끝의 .md를 찾습니다. 여기서 점 앞의 역슬래시를 빼면 .이 실제 점이 아니라 임의의 문자 한 개를 뜻하게 되니 주의해야 합니다. 여러 줄에서 각 행의 시작과 끝을 찾고 싶을 때는 m 플래그를 켜면 되는데요. Markdown 제목을 찾을 때 ^#과 함께 쓸 수 있습니다.

여러 패턴을 묶기

확장자가 jpg, png, gif 중 하나인 문자열을 찾으려면 \.(jpg|png|gif)$로 적을 수 있습니다. 괄호로 세 확장자를 묶고 |로 선택지를 나눴습니다. 점 뒤에 세 확장자 중 하나가 와야 하고, 그 뒤에서 문자열이 끝나야 합니다.

괄호를 빼면 적용 범위가 달라집니다. \.jpg|png는 .jpg 또는 png를 찾습니다. png 앞에 점이 없어도 되고, 뒤에 다른 문자가 이어져도 됩니다. 공통으로 적용할 조건이 있다면 괄호를 어디에 놓는지 확인해야 합니다.

찾은 내용을 다시 쓰기

날짜의 연도·월·일 순서를 바꾸고 싶다면 각각을 괄호로 묶어 캡처 그룹으로 기억해 두면 됩니다. 치환할 때 원하는 순서로 다시 꺼내 쓰는 거죠. 아래 예제는 sed에 -E 옵션을 붙여 확장 정규식을 사용합니다.

Reorder a date with sed -E

printf '%s\n' '2026-08-03' | sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3\/\2\/\1/'

첫 번째 괄호는 2026, 두 번째는 08, 세 번째는 03에 해당합니다. 치환 부분에 \3, \2, \1을 쓰면 일·월·연도 순서인 03/08/2026이 됩니다.

Vim의 :%s나 IDE의 찾기·바꾸기에서도 캡처한 내용을 다시 쓸 수 있습니다. 다만 도구에 따라 문법을 바꿔야 합니다. sed는 치환에 \1을 쓰지만 JavaScript의 replace()에서는 $1을 쓰고, Vim은 기본 설정에서 그룹 괄호에 역슬래시가 필요합니다.

색상 코드를 찾는 식 읽어 보기

#fff, #ffa142 같은 색상 코드를 찾는 식입니다.

Three or six lowercase hexadecimal digits

^#([0-9a-f]{3}|[0-9a-f]{6})$

^#으로 시작 문자를 확인한 뒤, [0-9a-f]로 숫자와 소문자 a부터 f까지 허용합니다. 여기에 {3}과 {6}으로 자릿수를 정하고 괄호와 |로 묶었으니 세 자리 또는 여섯 자리 중 하나에 맞아야 하죠. 끝의 $ 때문에 다른 문자가 뒤에 붙으면 일치하지 않으며, 대문자는 허용하지 않아 #FFF도 일치하지 않습니다.