on
정규표현식
정규표현식
프로그래머스 정규 표현식 코딩 실습을 하며 내용을 정리한 포스트입니다. 링크
정규 표현식이란
정규 표현식은 문자열에서 특정 패턴을 만족하는 부분을 찾아낼 때 사용합니다.
const searchTarget = `TaeYeong 010-1234-5667 [email protected] MinSu 02435-533454-322434 [email protected] MinJi 010 8765 4321 [email protected] hi 02-123-4567 [email protected]`;
사람 이름, 전화번호, 이메일이 적힌 문자열에서 전화번호만 찾는 정규식을 만들어 보겠습니다.
전화번호 찾기
전화번호를 찾기 위한 첫 단계는 숫자를 찾아내는 것 입니다.
match() 메서드를 이용하면 문자열에서 정규식에 해당하는 값을 찾아낼 수 있습니다.
숫자
\d 는 숫자를 대표하는 정규식 입니다. 이때 d 는 digit 을 의미합니다.
searchTarget.match(/\d/);
자바스크립트에서는 정규식을 / 로 감싸주어야 합니다.
[ '0', index: 9, input: 'TaeYeong 010-1234-5667 [email protected] MinSu 02435-533454-322434 [email protected] MinJi 010 8765 4321 [email protected] hi 02-123-4567 [email protected]', groups: undefined ]
이렇게 나오는데요, /\d/ 뒤에 g 를 붙이면 하나만 찾지 않고, 해당되는 모든 값을 찾아냅니다.
searchTarget.match(/\d/g);
[ '0', '1', '0', '1', '2', '3', '4', '5', '6', '6', '7', '0', '2', '4', '3', '5', '5', '3', '3', '4', '5', '4', '3', '2', '2', '4', '3', '4', '0', '1', '0', '8', '7', '6', '5', '4', '3', '2', '1', '0', '2', '1', '2', '3', '4', '5', '6', '7' ]
`test()` 메서드를 사용할 때 정규 표현식에 `g` 를 사용하면 안됩니다.
지금은 로컬에서 테스트를 하기위해 match() 메서드에 g 를 붙여서 하고있습니다.
비밀번호가 형식에 맞는지 확인하는 코드를 짜다 자꾸 오류가 생겼는데 알고보니 test() 메서드에 global flog 로 설정해준 정규 표현식을 사용해서 발생한 문제였습니다.
글자
\w 는 글자를 대표하는 정규 표현식입니다.
\w 는
a, b, c, 가, 나, 다, 1, 2 와 같은 문자와 숫자를 모두 포함합니다.
와 같은 문자와 숫자를 모두 포함합니다. 특수문자는 포함하지 않지만 _ 는 포함합니다.
searchTarget.match(/\w/g);
[ 'T', 'a', 'e', 'Y', 'e', 'o', 'n', 'g', '0', '1', '0', '1', '2', '3', '4', '5', '6', '6', '7', 't', 'a', 'e', 'y', 'e', 'o', 'n', 'g', 'g', 'm', 'a', 'i', 'l', 'c', 'o', 'm', 'M', 'i', 'n', 'S', 'u', '0', '2', '4', '3', '5', '5', '3', '3', '4', '5', '4', '3', '2', '2', '4', '3', '4', 'm', 'i', 'n', 's', 'u', 'g', 'm', 'a', 'i', 'l', 'c', 'o', 'm', 'M', 'i', 'n', 'J', 'i', '0', '1', '0', '8', '7', '6', '5', '4', '3', '2', '1', 'm', 'i', 'n', 'g', 'i', 'g', 'm', 'a', 'i', 'l', 'c', 'o', 'm', 'h', 'i', '0', '2', '1', '2', '3', '4', '5', '6', '7', 'h', 'i', 'g', 'm', 'a', 'i', 'l', 'c', 'o', 'm' ]
하나 이상
\d 는 숫자를 한 글자씩만 찾았습니다.
전화번호에서 1234 와 같이 연결된 숫자를 찾고 싶을 때는 + 를 이용합니다.
\d+ 는 '하나 혹은 그 이상 연결된 숫자' 를 의미합니다.
searchTarget.match(/\d+/);
[ '010', '1234', '5667', '02435', '533454', '322434', '010', '8765', '4321', '02', '123', '4567' ]
몇 개 중에 고르기
알파벳 소문자중 a, b, c, d, e 만 고르고 싶을때는 [abcde] 이렇게 적어주면 됩니다.
정규 표현식에서 대괄호 안에 글자를 넣으면 해당 글자를 모두 선택할 수 있습니다.
searchTarget.match(/[abcde]/g);
[ 'a', 'e', 'e', 'a', 'e', 'e', 'a', 'c', 'a', 'c', 'a', 'c', 'a', 'c' ]
범위에서 고르기
만약 소문자 알파벳을 고르고 싶다면 [abcdefghijklmnopqrstuvwxyz] 이렇게 하면 되겠죠?
이렇게 다 써도 되지만 더 편한 표현식이 있습니다.
[a-z] 인데요, 'a 부터 z 까지의 글자를 모두 선택' 이라는 의미입니다.
이것을 응용해서 연속된 영어 소문자를 찾고 싶을땐 [a-z]+ 이렇게 사용할 수 있습니다. 'a 부터 z 까지의 글자가 하나 또는 그 이상 연결되었다' 라는 뜻이니까요.
searchTarget.match(/[a-z]+/g);
[ 'ae', 'eong', 'taeyeong', 'gmail', 'com', 'in', 'u', 'minsu', 'gmail', 'com', 'in', 'i', 'mingi', 'gmail', 'com', 'hi', 'hi', 'gmail', 'com' ]
한글 고르기
한글은 [가-힣] 으로 찾을 수 있습니다.
이 방법으로는 ㄱㄴㄷ 이나 ㅏㅑㅓㅕ 같은 낱글자는 찾을 수 없습니다.
{: .notice}
0개 이상
만약 자연수를 찾고 싶다면
첫자리가 1~9 중에 하나여야 하고
그다음 자리부터는 0~9 사이의 숫자가 나올 수도 있고, 나오지 않을 수도 있습니다.
이것을
처음에 1~9 중 하나의 숫자가 나온 다음 그 뒤에 숫자가 0개 이상이면
이렇게 정규 표현식으로 표현하면 됩니다.
* 은 '0개 이상' 이라는 뜻입니다. \d* 는 '숫자가 0개 이상이다' 를 의미합니다.
이를 이용하면 자연수는 [1-9]\d* 로 표현할 수 있습니다.
searchTarget.match(/[1-9]\d*/);
[ '10', '1234', '5667', '2435', '533454', '322434', '10', '8765', '4321', '2', '123', '4567' ]
있거나 없거나
전화번호는 - 을 포함하거나 포함하지 않을 수 있습니다.
01012345678 010-1234-5678
이런식으로 말이죠.
따라서 전화번호는 '연속되는 숫자 사이에 - 가 있거나 없다' 고 표현할 수 있습니다.
? 는 '있거나 없거나' 라는 뜻입니다. -? 는 ' - 가 있거나 없다' 를 의미합니다.
이것을 적용시켜보면 \d+-?\d+=?\d+ 이런 표현식을 만들수 있습니다.
searchTarget.match(/\d+-?\d+-?\d+/g);
[ '010-1234-5667', '02435-533454-322434', '010', '8765', '4321', '02-123-4567' ]
있거나 없거나 2
\d+-?\d+-?\d+ 은 문제가 있었습니다.
'010 8765 4321' 과 같이 공백으로 입력한 전화번호는 각각 쪼개져서 출력되었습니다.
01012345678 010-1234-5678 010 1234 5678
이런 형식의 전화번호들을 모두 찾으려면 ' - 가 있거나 없다' 라는 조건 대신 ' - 또는 공백이 있거나 없다' 라는 조건을 사용해야 합니다.
- 또는 공백이 있거나 없다는 조건은 [- ]? 로 표현할 수 있습니다.
정규 표현식 \d+[- ]?\d+[- ]?\d+ 를 사용해 보겠습니다.
searchTarget.match(/\d+[- ]?\d+[- ]?\d+/g);
[ '010-1234-5667', '02435-533454-322434', '010 8765 4321', '02-123-4567' ]
n개
정규 표현식 \d+[- ]?\d+[- ]?\d+ 도 전화번호를 찾는데 한계가 있었습니다.
위의 예제에서 '02435-533454-322434' 라는 문자열도 전화번호로 인식했습니다.
{숫자} 는 ' 숫자 번 반복한다' 라는 뜻입니다.
예를들어 \d{2} 는 '숫자가 연속 2번 나온다' 라는 뜻입니다.
이것을 적용해보면 \d{3}[- ]?\d{4}[- ]?\d{4} 이렇게 하면 되겠죠?
searchTarget.match(/\d{3}[- ]?\d{4}[- ]?\d{4}/g);
[ '010-1234-5667', '010 8765 4321' ]
n~m 개
정규 표현식 \d{3}[- ]?\d{4}[- ]?\d{4} 는 000-0000-0000 형식의 전화번호만 인식할 수 있습니다.
그래서 '02-123-4567' 라는 번호가 출력되지 않았습니다.
{숫자1,숫자2} 는 ' 숫자1 부터 숫자2 까지 반복한다' 라는 뜻입니다.
예를들어 \d{2, 3} 은 '숫자가 2~3번 나온다' 라는 뜻입니다.
모든 전화번호는 처음 자릿수가 2
3자리 가운데 자릿수가 3
4자리, 마지막 자릿수가 4자리 입니다.
이것을 정규 표현식으로 표현하면 \d{2,3}[- ]?\d{3,4}[- ]?\d{4} 로 표현할 수 있습니다.
{2, 3} 처럼 , 뒤에 공백을 넣으시면 안됩니다! 왜 안되는건지 찾는다고 고생했네요 ㅜㅜ
{: .notice}
searchTarget.match(/\d{2,3}[- ]?\d{3,4}[- ]?\d{4}/g);
[ '010-1234-5667', '02435-5334', '010 8765 4321', '02-123-4567' ]
선택
여기서 또 문제가 있습니다.
'02435-533454-322434' 라는 문자열중 '02435-5334' 가 선택되어 출력되었습니다.
위에서 사용한 [- ]? 는 ' - 나 공백이 있거나 없다' 라는 뜻이기 때문에 '2자리 숫자뒤에 3자리 숫자 뒤에 - 뒤에 숫자 4자리' 라는 조건을 만족하는 '02435-5334' 가 출력된 것 입니다.
(다른 방법이 있겠지만) 저는 '01012345678' 형식의 전화번호를 선택하는 것을 포기하고 '02435-5335' 와 같은 문자열을 전화번호로 선택하지 않는 것이 더 나을 것 같다고 생각했습니다.
그래서 [- ]? 대신 [- ] 로 바꾸어 주었습니다.
[- ] 는 ' - 또는 공백이 있다' 라고 해석됩니다.
searchTarget.match(/\d{2,3}[- ]\d{3,4}[- ]\d{4}/g);
[ '010-1234-5667', '010 8765 4321', '02-123-4567' ]
Reference
프로그래머스 정규표현식{:target="_blank"}
from http://dev-taeyeong.tistory.com/15 by ccl(A) rewrite - 2021-12-25 23:02:49