텍스트를 다루는 방법은 4.3절에서 어느 정도 설명했다. 이 절에서는 텍스트를 양식에 맞추어 가공하는 방법과 re 모듈을 이용해 패턴을 탐색하는 방법을 다룬다.

11.2.1 텍스트 양식화

텍스트 양식화란 데이터를 텍스트 양식에 적용해 양식에 알맞는 텍스트를 만들어내는 것이다. 가령, score = 20이라는 변수를 '점수: {score} 점'이라는 양식에 적용한다면, '점수: 20 점'이라는 텍스트가 될 것이다. 지금까지는 str() 함수와 문자열 연결 연산(+)을 통해 이를 수행해 왔다.

코드 11-14 문자열 연결 연산을 통한 양식화

>>> score = 20
>>> '점수: ' + str(score) + ' 점'
'점수: 20 점'

양식을 한 번 만들어 두면 여러 가지 데이터를 동일한 양식의 텍스트로 변환할 수 있다. 코드 11-14의 양식화 코드는 일회성이지만, 함수로 정의해두면 양식화가 필요할 때마다 재사용할 수 있다.

코드 11-15 텍스트 양식화 함수 정의하기

>>> def format_score(score):
...     """'점수: score 점' 양식의 텍스트를 반환한다."""
...     return '점수: ' + str(score) + ' 점'
... 
>>> format_score(25), format_score(30)
('점수: 25 점', '점수: 30 점')

str() 함수와 문자열 연결 연산을 통한 양식화는 이해하기 어렵지 않지만, 코드가 길어지기 쉽고 양식을 알아보기가 어렵다.

코드 11-16 문자열 연결 연산을 통한 양식화는 알아보기 불편하다

>>> physics, chemistry, biology = 80, 90, 70
>>> '물리학: ' + str(physics) + ', 화학: ' + str(chemistry) + ', 생물학: ' + str(biology)
'물리학: 80, 화학: 90, 생물학: 70'

코드 11-16을 보면, '물리학: 80, 화학: 90, 생물학: 70'이라는 간단한 양식을 나타내는 데도 제법 긴 코드가 필요하다. 연산자를 빠트리거나 띄어쓰기를 틀리는 등 실수를 저지르기도 쉽다. 텍스트 양식화는 프로그래밍에서 상당히 자주 필요한 기능이므로 좀더 편리하고 직관적으로 수행하는 방법이 필요하다. 파이썬은 이를 위해 format() 메서드와 양식 문자열 리터럴을 제공한다.

format() 메서드

문자열(str) 클래스에는 format()이라는 메서드가 있다. ‘format’은 ‘양식화하다’라는 뜻이며, 이 메서드는 문자열을 양식으로 삼아 데이터를 양식화해 준다. 다음 예를 보고 이야기해 보자.

코드 11-17 format() 메서드를 사용한 양식화

>>> form = '물리학: {}, 화학: {}, 생물학: {}'  # 양식 문자열 정의
>>> form.format(physics, chemistry, biology)   # 양식 채워넣기
'물리학: 80, 화학: 90, 생물학: 70'

문자열은 그 자체로 양식이 될 수 있다. 문자열 속에 중괄호({})로 데이터를 채워넣을 수 있는 빈 칸을 만들어주기만 하면 된다. 이런 텍스트 양식은 텍스트 연결 연산 식보다 훨씬 알아보기 쉽다.

그 뒤에는 정의해 둔 양식 문자열에 format() 메서드를 호출해 채워 넣을 데이터를 인자로 전달하기만 하면 된다. 나머지 작업은 format() 메서드가 알아서 처리한다. 데이터를 문자열로 변환할 필요도 없고, 문자열을 하나하나 연결하지 않아도 된다.

데이터를 어떤 양식에 맞춰 출력해야 한다면 항상 format() 메서드와 양식 문자열을 사용하는 것이 좋다.

format() 메서드를 위한 양식 문자열 작성 규칙

양식 문자열을 작성할 때는 일정한 규칙에 따라야 한다. 가장 간단한 규칙은 데이터를 위한 빈 칸을 중괄호로 표현해야 한다는 것이다. 그 외에도 여러 가지가 있으니 다음 내용을 살펴봐 두자. 물론, 당장 다 외울 필요는 없다.

format() 메서드는 데이터를 전달된 순서대로 양식에 포함시킨다. 순서를 조정해야 하거나, 순서를 좀더 정확히 나타내고 싶다면 {항목번호}와 같이 중괄호 속에 항목 번호를 적어준다. 번호는 0부터 시작한다.

코드 11-18 텍스트 양식에 항목 번호 명시하기

>>> '물리학: {0}, 생물학: {2}, 화학: {1}'.format(50, 60, 70)
'물리학: 50, 생물학: 70, 화학: 60'

format() 메서드에 시퀀스를 전달하는 경우 양식 속에 {항목번호[인덱스]}와 같이 표현하여 시퀀스의 요소를 출력할 수 있다.

코드 11-19 시퀀스의 요소 출력하기

>>> '{0[0]}년 {0[1]}월 {0[2]}일'.format([2017, 11, 20])
'2017년 11월 20일'

매핑의 요소 역시 {항목번호[키]} 형식으로 출력할 수 있다. 이 때, 매핑의 키가 문자열이라도 따옴표 기호는 양식에 포함하지 않는다.

코드 11-20 매핑의 요소 출력하기

>>> '{0[h]}시 {0[m]}분 {0[s]}초'.format({'h': 16, 'm': 30, 's': 0})
'16시 30분 0초'

이름공간에 정의된 이름(모듈 속의 이름 또는 클래스·인스턴스의 속성)이 가리키는 값을 출력하려면 양식을 {항목번호.이름}과 같이 작성한다.

코드 11-21 이름공간의 이름이 가리키는 값 출력하기

>>> import math
>>> '원주율: {0.pi}'.format(math)
'원주율: 3.141592653589793'

여러 데이터의 출력 길이가 일정하지 않으면 양식이 일정하게 통일되지 않는 문제가 있다. 다음 예를 보자.

코드 11-22 데이터의 출력 길이가 서로 맞지 않을 때

>>> countries = [
...     {'name': 'China', 'population': 1403500365},
...     {'name': 'Japan', 'population': 126056362},
...     {'name': 'South Korea', 'population': 51736224},
...     {'name': 'Pitcairn Islands', 'population': 56},
... ]
>>> form = '나라: {0} | 인구: {1}'
>>> for country in countries:
...     print(form.format(country['name'], country['population']))
... 
나라: China | 인구: 1403500365
나라: Japan | 인구: 126056362
나라: South Korea | 인구: 51736224
나라: Pitcairn Islands | 인구: 56

이럴 때 공백 문자를 이용해 자리를 일정 길이만큼 채우도록 할 수 있다. {항목번호:자리길이}와 같은 형식을 사용하면 된다.

코드 11-23 자리 길이 지정하기

>>> form = '나라: {0:16} | 인구: {1:10}'
>>> for country in countries:
...     print(form.format(country['name'], country['population']))
... 
나라: China            | 인구: 1403500365
나라: Japan            | 인구:  126056362
나라: South Korea      | 인구:   51736224
나라: Pitcairn Islands | 인구:         56

자리길이를 나타내는 수 앞에 0을 붙이면 공백 대신 0으로 빈자리를 채울 수 있다.

코드 11-24 빈자리를 0으로 채우기

>>> form = '나라: {0:16} | 인구: {1:010}'
>>> for country in countries:
...     print(form.format(country['name'], country['population']))
... 
나라: China            | 인구: 1403500365
나라: Japan            | 인구: 0126056362
나라: South Korea      | 인구: 0051736224
나라: Pitcairn Islands | 인구: 0000000056

빈 자리만큼의 공백이 출력되는 위치는 데이터의 종류에 따라 다르다. 문자열은 왼쪽으로 정렬되지만, 수는 오른쪽으로 정렬되어 출력된다. < 기호로 왼쪽 정렬을, > 기호로 오른쪽 정렬을 강제 지정할 수 있다.

코드 11-25 자리 정렬 기준 지정하기

>>> form = '나라: {0:>16} | 인구: {1:>10}'
>>> for country in countries:
...     print(form.format(country['name'], country['population']))
... 
나라:            China | 인구: 1403500365
나라:            Japan | 인구:  126056362
나라:      South Korea | 인구:   51736224
나라: Pitcairn Islands | 인구:         56

이 외에도 양식 지정 규칙이 몇 가지 더 있지만 이 정도만 알아두어도 대부분의 작업에는 큰 문제가 없을 것이다.

양식 문자열 리터럴

양식 문자열 리터럴(formatted string literal, f-string)은 문자열 속의 식을 그 평가 결과로 치환하는 문자열이다. 이 기능은 파이썬 버전 3.6에서 새로 도입된 기능이어서 그보다 낮은 버전에서는 사용할 수 없다.

양식 문자열 리터럴을 작성할 때는 f'문자열'과 같이 문자열을 나타내는 따옴표 기호 앞에 f를 붙인다. 그리고 평가하려는 식을 중괄호 안에 삽입한다.

코드 11-26 양식 문자열 리터럴로 과목별 성적 양식화하기

>>> physics, chemistry, biology = 80, 90, 70
>>> f'물리학: {physics}, 화학: {chemistry}, 생물학: {biology}'
'물리학: 80, 화학: 90, 생물학: 70'

변수의 이름을 평가하는 것 뿐 아니라, 다른 식도 평가할 수 있다.

코드 11-27 양식 문자열 리터럴로 과목 점수 합계 평가하기

>>> f'총점: {physics + chemistry + biology}'
'총점: 240'

양식 문자열 리터럴에서도 자리 길이 지정 등 앞서 살펴본 다양한 양식 규칙을 적용할 수 있다. 다음 예는 for 문, range() 함수, 양식 문자열 리터럴을 이용해 제곱 곱셈표를 출력해 본 것이다.

코드 11-28 양식 문자열 리터럴로 제곱 곱셈표 출력하기

>>> for i in range(2, 10):
...     for j in range(1, 10):
...         print(f'{i} ** {j} = {i ** j:10}')
... 
2 ** 1 =          2
2 ** 2 =          4
2 ** 3 =          8
2 ** 4 =         16
2 ** 5 =         32
2 ** 6 =         64
2 ** 7 =        128
2 ** 8 =        256
2 ** 9 =        512
(...중략...)
9 ** 1 =          9
9 ** 2 =         81
9 ** 3 =        729
9 ** 4 =       6561
9 ** 5 =      59049
9 ** 6 =     531441
9 ** 7 =    4782969
9 ** 8 =   43046721
9 ** 9 =  387420489

양식 문자열과 format() 메서드는 양식을 변수에 대입해두고 자주 재사용해야 할 때 유용하다. 만약 양식을 한번만 사용할 것이라면 format() 메서드 없이 양식 문자열 리터럴을 사용하는 편이 더 간편할 수 있다.

개념 정리

  • 텍스트 양식화: 양식을 정의한 뒤, format() 메서드로 양식화된 문자열을 구할 수 있다.
  • 양식을 변수에 저장할 필요가 없다면 양식 문자열 리터럴을 사용해도 편리하다.

11.2.2 텍스트 패턴

텍스트 데이터를 다루다 보면 텍스트에서 일정한 패턴을 찾아야 할 때가 있다. 패턴이란 이메일 주소 형식, ‘한글 문자 연속 세 개’, ‘열 자리 숫자’ 등 텍스트가 배열된 규칙을 뜻한다. 이처럼 텍스트의 패턴을 나타내는 텍스트를 정규식(regular expression)이라고 부른다.

어떤 텍스트에서 지정한 패턴이 발견될 때 ‘텍스트에 패턴이 매치한다’라고 한다. 패턴 매치를 활용하면 텍스트가 올바른 형식인지, 텍스트에 어떤 내용이 포함되어 있는지 등을 확인할 수 있다. 예를 들어, 사용자가 입력한 이메일 주소가 올바른 형식인지 검사하거나, 문서에서 한글이 몇 자이고 알파벳이 몇 자인지 셀 수도 있다. 정규식은 텍스트를 다루는 대부분의 프로그램에서 유용하게 활용된다.

개념 정리

  • 패턴: 텍스트가 배열된 규칙
  • 텍스트에서 패턴을 매치하여 찾거나 조작할 수 있다.

정규식 처리 메서드

표준 라이브러리의 re 모듈은 패턴과 매치하는 텍스트를 찾고 조작하는 기능을 제공한다. 이 모듈에서 자주 사용되는 함수를 표 11-6에 정리해 두었다.

함수 값 또는 기능
re.compile(pattern) 패턴 문자열 pattern을 패턴 객체로 컴파일한다
re.search(pattern, string) string에서 pattern과 매치하는 텍스트를 탐색한다 (임의 지점 매치)
re.match(pattern, string) string에서 pattern과 매치하는 텍스트를 탐색한다 (시작점 매치)
re.fullmatch(pattern, string) string에서 pattern과 매치하는 텍스트를 탐색한다 (전체 매치)
re.sub(pattern, repl, string) string에서 pattern과 매치하는 텍스트를 repl로 치환한다
re.split(pattern, string) stringpattern을 기준으로 나눈다

표 11-6 re 모듈에서 자주 사용되는 함수

가장 간단한 패턴은 매치하려는 텍스트와 완전히 일치하는 텍스트다. 예를 들어, '파이썬' 이라는 패턴은 '파이썬' 이라는 텍스트와 매치한다. 이 텍스트로 표 11-6의 함수들을 시험해 보자.

패턴은 간단히 문자열로 정의하면 되고, 그 패턴 문자열을 re.compile() 메서드에 전달해 패턴 객체를 생성해 두어도 된다. 정의한 문자열 또는 패턴 객체는 re.search() 등 다른 메서드의 패턴 인수로 전달할 때 사용한다.

코드 11-29 정규식을 패턴 객체로 컴파일하기

>>> import re                             # 정규식 모듈 임포트
>>> pattern_string = r'파이썬'            # '파이썬' 패턴 문자열
>>> pattern = re.compile(pattern_string)  # 패턴 문자열을 패턴 객체로 컴파일

패턴을 나타내는 문자열 r'파이썬' 앞에 r이 붙어 있다. 패턴에는 다양한 기호가 포함되는데 이스케이프가 되면 곤란할 때가 많다. 문자열 앞에 r을 붙여 이스케이프를 방지하는 편이 좋다.(4.3절 참고)

문자열에서 패턴 탐색하기

이제 '파이썬' 패턴을 텍스트와 매치해 보자. 문자열에서 패턴과 매치하는 텍스트를 탐색하려면 re.search() 함수를 사용한다. 문자열에서 매턴이 매치했다면 Match 객체가 반환되고, 그렇지 않으면 None이 반환된다. 대화식 셸에서는 None이 반환되었을 때 화면 출력이 생략된다는 점을 기억하자.

코드 11-30 re.search() 함수로 문자열에서 패턴 탐색하기

>>> re.search(pattern, '파이썬')         # 매치한다: Match 객체 반환
<_sre.SRE_Match object; span=(0, 3), match='파이썬'>

>>> re.search(pattern, '즐거운 파이썬')  # 일부 텍스트와 매치한다
<_sre.SRE_Match object; span=(4, 7), match='파이썬'>

>>> re.search(pattern, '파이프')         # 매치하지 않는다: None 반환

re.search() 함수 대신 re.match() 함수나 re.fullmatch()함수를 사용할 수도 있다. 세 함수는 하는 일이 비슷하며, 문자열에서 패턴을 매치시킬 위치를 제약하는 정도에만 차이가 있다. re.search()는 문자열의 어느 위치에서나 패턴이 매치할 수 있지만, re.match()는 문자열의 시작점에서만 패턴이 매치할 수 있고, re.fullmatch()는 문자열의 시작부터 끝까지 전체 매치만 가능하다. 이 세 함수로 Python 패턴을 여러 가지 텍스트에서 탐색한 결과를 표 11-7에 비교해 두었다.

함수 Python Python programming Hi, Python
re.search() Match Match Match
re.match() Match Match None
re.fullmatch() Match None None

표 11-7 세 함수의 Python 패턴 탐색 결과 비교

re.search(), re.match(), re.fullmatch() 세 함수는 패턴이 텍스트와 매치할 때 Match 객체를 반환한다. Match 객체는 참으로 평가되며, None은 거짓으로 평가된다. 그래서 re.search() 함수의 반환 값을 if 문 등의 조건으로 사용할 수도 있다.

코드 11-31 매치 결과를 조건으로 사용하기

match = re.search('파이썬', '파이썬 프로그래밍')
if match:
    print('문자열에 패턴과 매치하는 텍스트가 존재함')
else:
    print('문자열에 패턴과 매치하는 텍스트가 존재하지 않음')

패턴과 매치한 텍스트는 Match 객체의 group() 메서드로 구할 수 있다.

코드 11-32 패턴과 매치한 텍스트 구하기

>>> match = re.search(pattern, '즐거운 파이썬 프로그래밍')
>>> match.group()
'파이썬'

문자열 치환하기, 분리하기

re.sub() 함수는 문자열에서 매치된 텍스트를 다른 텍스트로 치환할 때 사용한다. ‘sub’는 치환을 뜻하는 ‘substitution’의 줄임말이다. 패턴이 여러 번 매치하면 매치한 텍스트를 모두 치환한다.

코드 11-33 re.sub() 함수로 문자열 치환하기

>>> re.sub(pattern, '리스프', '즐거운 파이썬 프로그래밍')
'즐거운 리스프 프로그래밍'

>>> re.sub(' ', '*', '즐거운 파이썬 프로그래밍')
'즐거운*파이썬*프로그래밍'

re.split() 함수는 지정한 패턴을 기준으로 문자열을 나눈다. 나누어진 문자열은 리스트에 담겨 반환된다.

코드 11-34 re.split() 함수로 문자열 나누기

>>> re.split(pattern, '즐거운 파이썬 프로그래밍')
['즐거운 ', ' 프로그래밍']

정규식의 특수 기호

앞에서 살펴본 re 모듈의 함수들이 수행하는 패턴 탐색, 문자열 치환, 분자열 분리 작업은 일반 문자열 객체의 메서드(find(), replace(), split(). 4.3절 참고)로도 수행할 수 있다. re 모듈의 함수는 일반 문자열 대신 패턴을 기준으로 치환과 분리를 수행한다는 점이 차이인데, 단순히 동일한 문자열을 매치하는 패턴을 사용한다면 일반 문자열 메서드와 다를 바 없다.

정규식은 좀 더 복잡한 패턴을 매치할 때 의미가 있다. 그러한 패턴을 작성하려면 다양한 특수 기호의 의미를 알아야 한다. 다음 표를 간단히 훑어본 뒤 예제를 살펴보자.

특수 기호 의미
. 개행 문자를 제외한 아무 문자 하나 파..: 파이썬, 파랑새, 파김치와 매치
^ 텍스트의 시작지점 ^a: ab와 매치, ba와는 매치하지 않음
$ 텍스트의 종료지점 a$: ba와 매치 ab와는 매치하지 않음
+ 앞의 문자가 1번 이상 등장 ab+: ab, ab, abbbb 등과 매치
? 앞의 문자가 0번 또는 1번만 등장 ab?: a, ab와 매치
* 앞의 문자가 0번 이상 등장 ab*: a, ab, abbb 등과 매치
{n} 앞의 문자가 n번 등장 ab{3}: abbb와 매치
{m,n} 앞의 문자가 m - n번 등장 ab{1,3}: ab, abb, abbb와 매치
(a|b) a 또는 b a(b|c): ab, ac와 매치
[문자들] 대괄호 속의 문자 중 하나 a[bcd]: ab, ac, ad와 매치
[^문자들] 대괄호 속의 문자가 아닌 문자 하나 a[^bcd]: aa, ae, af등과 매치
[0-9] 0, 9 사이의 모든 문자 [0-9]+: 0, 1234 등과 매치
[A-Z] A, Z 사이의 모든 문자 [A-Z]+: I, PYTHON 등과 매치
[a-z] a, z 사이의 모든 문자 [A-Z][a-z]+: Aa, Python 등과 매치
[가-힣] , 사이의 모든 문자 [가-힣]+: 파이썬, 프로그래밍 등과 매치

표 11-8 정규식의 특수 기호

표만 봐서는 특수 기호들이 어디에 쓰는 것인지 알기 어려울 것이다. 간단한 예제 패턴을 작성하면서 익혀 보자.

한국 사람 이름과 매치하는 패턴

'1789Python김파이fog'와 같은 임의의 문자열에서 한국 사람의 이름을 매치하는 패턴을 작성해보자. 먼저 이름을 판단할 규칙부터 생각해 보아야 한다. 나는 ‘한글 두 자에서 한글 네 자 사이의 문자열’로 정했다. 물론 여기에 어긋나는 이름도 있을 수 있고, 이름이 아닌 한글 단어가 매치될 수도 있지만, 더 정교한 매치를 하려면 정규식이 복잡해지니 이 정도로 만족하자.

한글 하나를 나타내려면 패턴을 [가-힣]과 같이 작성한다. 대괄호는 그 안의 모든 문자 중 하나와 매치하겠다는 뜻이고, 대괄호 안에 -를 쓸 경우 두 문자 사이의 모든 문자를 의미한다. 유니코드의 한글 배열 순서에서 는 한글의 첫번째 글자이고, 은 마지막 글자다. 따라서 [가-힣]은 모든 한글(단, 자모는 제외) 글자를 뜻한다.

그런데, 한글 하나가 아니라 여럿을 매치해야 한다. 이를 간단히 나타내려면 패턴을 반복 작성하면 된다. 예를 들어, 한글 두 글자는 [가-힣][가-힣]으로 매치할 수 있다. 한글 세 글자 또는 두 글자와 매치하고 싶다면, (a|b) 기호를 이용해 ([가-힣][가-힣][가-힣])|([가-힣][가-힣])으로 나타낼 수 있다. 하지만 이런 반복은 너무 불편하므로 다른 {m,n} 특수 기호를 이용하자. [가-힣]{2,4}로 한글이 두 자에서 네 자 사이인 텍스트를 매치할 수 있다.

완성한 정규식은 파이썬에서 re 모듈로 활용할 수 있다.

코드 11-35 한국 사람 이름 매치하기

>>> sample = '1789Python김파이fog'         # 샘플 텍스트
>>> pattern = re.compile(r'[가-힣]{2,4}')  # 패턴
>>> match = re.search(pattern, sample)     # 매치 결과를 match 변수에 대입
>>> match.group()                          # 매치한 텍스트 구하기
'김파이'

휴대전화번호와 매치하는 패턴

한가지 예만 더 살펴보자. 이번에는 휴대전화번호를 매치하는 규칙을 작성해 보자. 먼저, 한국의 휴대전화번호 형식을 생각해보면, 01X-XXXX-XXXX 또는 01X-XXX-XXXX 같은 형식을 사용하며, 여기서 X는 0에서 9 사이의 아무 수다. 이를 정규식으로 나타내면 01[0-9]-[0-9]{3,4}-[0-9]{4}가 된다.

그런데 숫자 [0-9]는 정규식에서 자주 매치해야 하는 문자임에도 매번 대괄호 속에 나열해야 하여 불편하다. 정규식 규칙 중에는 숫자 문자 집합을 간편하게 \d로 나타내기로 한 약속이 있다. 이를 적용하면 같은 정규식을 01\d-\d{3,4}-\d{4}로 좀더 간결하게 나타낼 수 있다. 이처럼 자주 사용되는 문자 집합을 나타내는 특수 기호를 표 11-9에서 간단히 정리해 두었으니 참고하자. (아쉽게도 한글을 나타내는 특수 기호는 없으므로 불편하더라도 [가-힣]으로 표현해야 한다.)

특수 기호 의미 비슷한 표현[^주의1]
\\ 백슬래시(\)  
\d 모든 숫자 [0-9]
\D 숫자 외의 문자 [^0-9]
\s 공백 문자 [ \t\n\r\f\v]
\S 공백 문자 외의 문자 [^ \t\n\r\f\v]
\w 숫자·알파벳·한글 등을 포함한 문자 [가-힣a-zA-Z0-9_]
\W 문자 외의 기호 [^가-힣a-zA-Z0-9_]

표 11-9 정규식의 문자 집합 기호

[^주의1]: 이 표의 ‘비슷한 표현’은 참고를 위한 것일 뿐, 반드시 동일하지는 않다. 예를 들어, \w는 알파벳과 한글 외에 다른 여러 언어의 문자도 포함한다.

이제 작성한 정규식을 패턴 객체로 컴파일하여 텍스트 샘플과 매치해보자. 휴대전화번호를 올바르게 추출할 수 있을 것이다.

코드 11-36 휴대전화번호 매치하기

>>> sample = '이름: 김파이, 연락처: 010-1234-5678, 주소: 부산 어딘가'
>>> pattern = re.compile(r'01\d-\d{3,4}-\d{4}')
>>> match = re.search(pattern, sample)
>>> match.group()
'010-1234-5678'

정규식의 기초적인 기능만 살펴봤지만 이것만으로도 다양한 텍스트 처리 상황에 대응할 수 있다. 여기서 연습해 본 요령으로 간단한 패턴은 쉽게 작성할 수 있을 것이다. 프로그래밍을 수행하면서 정규식을 작성해야 하는 일은 자주 있다. 기회가 될 때마다 연습하고 공부해두면 도움이 된다. 정규식을 더 잘 작성하고 싶다면 간결하고 쉬운 책 『손에 잡히는 정규표현식』(벤 포터 저, 김경수 역, 인사이트)을 읽어볼 것을 추천한다.

연습문제

연습문제 11-2 한글만 남기기

한글을 제외한 모든 문자를 나타내는 패턴 not_hangul_pattern을 정의해라. 그리고 이를 활용해 전달받은 문자열에서 한글만 남겨 반환하는 함수 hangul_only(string)를 정의해라.

이 함수를 호출하는 다음 코드를 실행하면,

print(hangul_only('I like 파이썬 programming.'))
print(hangul_only('a1가b2나c3다d4라e5마f6바g7사'))

다음과 같은 결과가 출력되어야 한다.

파이썬
가나다라마바사