파이썬 정규표현식(re) 사용법 - 07. 예제(숫자)
06 Aug 2018 | Regex re목차
파이썬 정규표현식(re) 사용법 - 01. Basic
파이썬 정규표현식(re) 사용법 - 02. 문자, 경계, flags
파이썬 정규표현식(re) 사용법 - 03. OR, 반복
파이썬 정규표현식(re) 사용법 - 04. 그룹, 캡처
파이썬 정규표현식(re) 사용법 - 05. 주석, 치환, 분리
파이썬 정규표현식(re) 사용법 - 06. 치환 함수, 양방탐색, 조건문
파이썬 정규표현식(re) 사용법 - 07. 예제(숫자)
파이썬 정규표현식(re) 사용법 - 08. 예제(단어, 행)
파이썬 정규표현식(re) 사용법 - 09. 기타 기능
이 글에서는 정규표현식으로 처리할 수 있는 예제를 설명한다.
본 글에서 정규표현식은 regex
와 같이, 일반 문자열은 ‘regex’와 같이 표시하도록 한다.
파이썬 버전은 3.6을 기준으로 하나, 3.x 버전이면 (아마) 동일하게 쓸 수 있다.
2.7 버전은 한글을 포함한 비 알파벳 문자 처리가 다르다.
숫자
십진 정수
문제 1: 가장 간단한 십진 정수를 찾는 정규식을 작성하라.
문제 1 정답보기
r'\b[0-9]+\b'
문제 2: 가장 일반적인 형태의 십진 정수를 찾는 정규식을 작성하라. 맨 앞에 ‘+’ 혹은 ‘-‘ 기호가 붙어 있을 수 있으며, 기호와 숫자 사이에는 공백이 하나 있을 수 있다.
문제 2 정답보기
r'(?:[+-] ?)?\b\d+\b'
비 아스키 숫자를 포함하고 싶다면 \d
를, 오로지 아라비아 숫자 10개만 숫자로 인식하게 하고 싶다면 [0-9]
를 사용하도록 한다.
또한 문자열 전체에 일치되게 하고 싶다면 \A
와 \Z
를 사용하면 된다.
십진 정수의 leading-zero 제거
문제 3: 십진 정수의 앞에 오는 0들을 제거하는 정규식을 작성하라. 기호는 없다고 가정하자.
문제 3 정답보기
re.sub(r'\b0*([1-9][0-9]*|0)\b', r'\1', string)
leading-zero가 될 수 있는 부분과 그렇지 않은 부분을 구분하기만 하면 이 문제는 풀린다. 그리고 leading-zero를 제거하는 것이 목표이므로 캡처된 부분으로 re.sub 메서드를 쓰면 해결된다.
한 가지 주의점은 ‘0’ 또는 ‘00’ 등 진짜 0밖에 없는 경우이다. 이 경우 0을 하나 남겨두어야 하기 때문에, leading-zero 뒤 숫자 부분에서 0을 한 개 남겨 두었다(|0
).
16진수
문제 4: 16진수를 찾는 정규식을 작성하라. 0-9의 숫자와 A-F 알파벳만 쓴다고 하자.
문제 4 정답보기
r'\A[0-9A-F]+\Z'
문제 5: 16진수를 찾는 정규식을 작성하라. 16진수는 아라비아 숫자 10개 또는 A-F, a-f를 사용하되 대문자와 소문자를 섞어 쓰지는 않는다. 또한, 16진수임을 나타내기 위해 숫자 바로 앞에 ‘0x’나 ‘&H’(hexa의 의미)를 붙이거나, 혹은 숫자 뒤에 ‘H’를 붙인다.
문제 5 정답보기
r'(\b0x|&H)?(?:[0-9A-F]+|[0-9a-f]+)(?(1)|H?)\b'
꽤 어려워 보일 것이다. 정규식은 복잡해지면 주석이 꼭 필요하다.
(\b0x|&H)?
: 보통 단어 경계를 맨 앞에 두는데, 이번엔 다자택일 중 하나에 두었다. 이유는 엠퍼샌드(‘&’)는 문자 집합에 포함되지 않으므로 단어 경계를 쓰면 안 된다.- 앞에 16진수 식별자를 두는 것은 선택적이므로
?
를 쓴다. - 그리고 이 부분은 첫 번째 캡처 그룹을 형성한다.
- 앞에 16진수 식별자를 두는 것은 선택적이므로
(?:[0-9A-F]+|[0-9a-f]+)
: 16진수 숫자를 나타내는 부분만 빼고 싶다면 앞부분의 비 캡처 그룹임을 의미하는?:
를 빼면 된다.- 대소문자 혼용을 허용하지 않았으므로 대문자를 쓸 때와 소문자를 쓸 때를 분리하였다.
(?(1)|H?)
: 조건문이다. 첫 번째 캡처 그룹에서 만약에 ‘0x’나 ‘&H’가 일치되었으면, 뒤에 또 ‘H’ 식별자를 두지는 않는다. 따라서 일치되었으면(‘맞으면’) 아무것도 없는 경우를, 일치되지 않았으면 ‘H’ 식별자를 선택적으로 일치시킬 수 있도록 한다.\b
: 단어 경계이다.
참고: 지정된 범위의 숫자인지 확인
이는 정규식으로 작성하길 추천하지 않는다. 아니면 함수로 따로 빼 두는 것을 추천한다.
그냥 숫자인지만 정규식으로 확인하고, 주어진 범위인지는 다른 함수로 확인하자.
그래도 예를 하나 들어 보겠다. 얼마나 복잡한지를 느끼면 된다.
문제 6: 1 이상 365 이하의 정수인지를 확인하는 정규식을 작성하라.
문제 6 정답보기
r'(36[0-5]|3[0-5][0-9]|[12][0-9]{2}|[1-9][0-9]?)'
그냥 따로 씁시다.
number = re.search('\d+', '몇 이상 몇 이하의 수 38개')
number = int(number.group())
if 1 <= number <= 365:
print('Yei!')
결과
Yei!
부동소수점 수
3번째 글의 끝에서 다음과 같은 문제가 있었다.
문제 7: 1.2이나 3.72e3, 1.002e-12 같은 수를 부동소수점 수 또는 과학적 표기법으로 표기한 수라고 한다. 이와 같은 수에 일치하는 정규표현식을 작성하라.
문제 7 정답보기
r'\b\d*\.\d+(e\d+)?'
조금 더 일반화한 버전을 문제로 하나 더 내 보았다.
문제 8 : 다음 조건에 맞는 부동소수점 수를 찾는 정규식을 작성하라.
- 부호부, 정수부, 가수부는 선택이다.
- 지수부 역시 선택이다.
- 정수부가 없으면 가수부는 필수이다.
- 가수부가 없으면 소수점은 선택이다.
문제 8 정답보기
r'[+-]?(\b[0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+\b)?'
정수부와 가수부가 동시에 없으면 안 되는 조건은 조건문을 사용해도 되고, 다자택일을 사용해도 된다. 이 경우는 다자택일을 사용했다.
로마 숫자
문제 9: 현대식 로마 숫자에 일치되는 정규식을 작성하라. ‘IV’는 가능하고, ‘IIII’는 불가능하다.
문제 9 정답보기
r'\b(?=[MDCLXVI])M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)\b'
(?=[MDCLXVI])
: 로마 숫자는 0이 없기 때문에, 문자가 하나라도 있는지 체크하는 전방탐색 구문이다.M*
: 로마 숫자에서 1000은 개수만큼 집어넣는다.-
` (C[MD] D?C*)`: 작은 숫자가 앞에 오는 경우를 따로 빼서 다자택일로 처리하였다. 로마 숫자의 규칙을 생각하면 그리 어려운 부분은 아니다. - 나머지 부분은 3번과 같다.
다음 글에서는 단어와 행 처리에 관한 예제를 다루도록 하겠다.