파이썬 정규표현식

Yeonu·2020년 11월 27일
4

Python 이론

목록 보기
28/30
post-thumbnail

👩‍💻 정규표현식

정규표현식(regular expression)은 일정한 규칙(패턴)을 가진 문자열을 표현하는 방법이다. 복잡한 문자열 속에서 특정한 규칙으로 된 문자열을 검색한 뒤 추출하고 바꿀 때 사용하거나 문자열이 정해진 규칙에 맞는지 판단할 때 사용한다.



👉 문자열 판단하기

문자열에 특정 문자열이 포함되어 있는지 판단한다. 정규표현식은 re 모듈을 가져와서 사용하며 match 함수에 정규표현식 패턴과 판단할 문자열을 넣는다(re는 regular expression의 약자).

re.match('패턴', '문자열')

>>> import re
>>> re.match('Hello', 'Hello, world!')     # 문자열이 있으므로 정규표현식 매치 객체가 반환됨
<_sre.SRE_Match object; span=(0, 5), match='Hello'>
>>> re.match('Python', 'Hello, world!')    # 문자열이 없으므로 아무것도 반환되지 않음



👉 문자열이 맨 앞에 오는지 맨 뒤에 오는지 판단하기

^문자열 : 문자열이 맨 앞에 오는지 판단한다.
문자열$ : 문자열이 맨 뒤에 오는지 판단한다(특정 문자열로 끝나는지).

이때는 match 대신 search 함수를 사용해야 한다.
match 함수 : 문자열 처음부터 매칭되는지 판단한다.
search 함수 : 문자열 일부분이 매칭되는지 판단다.

re.search('패턴', '문자열')



👉 지정된 문자열이 하나라도 포함되는지 판단하기

|는 특정 문자열에서 지정된 문자열(문자)이 하나라도 포함되는지 판단한다. 기본 개념은 OR 연산자와 같다.

문자열|문자열
문자열|문자열|문자열|문자열

>>> re.match('hello|world', 'hello')    # hello 또는 world가 있으므로 패턴에 매칭됨
<_sre.SRE_Match object; span=(0, 5), match='hello'>



👉 범위 판단하기

문자열이 숫자로 되어있는지 판단하기 : 대괄호 안에 0-9로 숫자 범위를 표현하고 *는 문자(숫자)가 0개 이상 있는지, +는 1개 이상 있는지 판단한다.

[0-9]*
[0-9]+



👉 문자가 한 개만 있는지 판단하기

? : 앞의 문자(범위)가 0개 또는 1개인지 판단한다.
. : .이 있는 위치에 아무 문자(숫자)가 1개 있는지 판단한다.

문자?
[0-9]?
.



👉 문자 개수 판단하기

문자{개수}
(문자열){개수}

특정 범위의 문자(숫자)가 몇 개 있는지 판단할 때는 범위 [ ] 뒤에 {개수} 형식을 지정한다.

[0-9]{개수}

문자(숫자)의 개수 범위도 지정할 수 있다. 주로 휴대전화 번호 형식에 사용한다.
(문자){시작개수,끝개수}
(문자열){시작개수,끝개수}
[0-9]{시작개수,끝개수}



👉 숫자와 영문 문자를 조합해서 판단하기

  • 영문자 범위
    a-z
    A-Z

  • 한글 범위
    가-힣

단순히 숫자인지 문자인지 판단할 때
\d: [0-9]와 같음. 모든 숫자
\D: [^0-9]와 같음. 숫자를 제외한 모든 문자
\w: [a-zA-Z0-9_]와 같음. 영문 대소문자, 숫자, 밑줄 문자
\W: [^a-zA-Z0-9_]와 같음. 영문 대소문자, 숫자, 밑줄 문자를 제외한 모든 문자



👉 특정 문자 범위에 포함되지 않는지 판단하기

  • 문자(숫자) 범위 앞에 ^를 붙이면 해당 범위를 제외한다.

[^범위]*
[^범위]+

'[^A-Z]+'는 대문자를 제외한 모든 문자(숫자)가 1개 이상 있는지 판단한다.

  • 특정 문자 범위로 시작할 때는 ^를 [ ] 앞에 붙여준다.

^[범위]*
^[범위]+

'^[A-Z]+'는 영문 대문자로 시작하는지 판단한다.

  • 특정 문자(숫자) 범위로 끝나는지 확인할 때는 정규표현식 뒤에 $를 붙인다.

[범위]*$

[범위]+$



👉특수 문자 판단하기

특수 문자 앞에 \를 붙인다. [ ] 안에서는 \를 붙이지 않아도 되지만 에러가 발생하는 경우에는 \를 붙인다.

>>> re.search('\*+', '1 ** 2')                    # *이 들어있는지 판단
<_sre.SRE_Match object; span=(2, 4), match='**'>
>>> re.match('[$()a-zA-Z0-9]+', '$(document)')    # $, (, )와 문자, 숫자가 들어있는지 판단
<_sre.SRE_Match object; span=(0, 11), match='$(document)'>



👉 공백 처리하기

' ' 혹은 \s 또는 \S

\s: [ \t\n\r\f\v]와 같음. 공백(스페이스), \t(탭) \n(새 줄, 라인 피드), \r(캐리지 리턴), \f(폼피드), \v(수직 탭)을 포함
\S: [^ \t\n\r\f\v]와 같음. 공백을 제외하고 \t, \n, \r, \f, \v만 포함



👉 그룹사용하기

정규표현식 그룹 : 해당 그룹과 일치하는 문자열을 얻어올 때 사용한다.

패턴 안에서 정규표현식을 ( )(괄호)로 묶으면 그룹이 된다.
(정규표현식) (정규표현식)

다음은 공백으로 구분된 숫자를 두 그룹으로 나누어서 찾은 뒤 각 그룹에 해당하는 문자열(숫자)을 가져온다.
매치객체.group(그룹숫자)

>>> m = re.match('([0-9]+) ([0-9]+)', '10 295')
>>> m.group(1)    # 첫 번째 그룹(그룹 1)에 매칭된 문자열을 반환
'10'
>>> m.group(2)    # 두 번째 그룹(그룹 2)에 매칭된 문자열을 반환
'295'
>>> m.group()     # 매칭된 문자열을 한꺼번에 반환
'10 295'
>>> m.group(0)    # 매칭된 문자열을 한꺼번에 반환
'10 295'
  • groups 메서드는 각 그룹에 해당하는 문자열을 튜플로 반환한다.
    매치객체.groups()

  • 그룹 개수가 많아지면 숫자로 그룹을 구분하기가 힘들어져 그룹에 이름을 지는다. 그룹의 이름은 ( )(괄호) 안에 ?P<이름> 형식으로 지정한다.
    (?P<이름>정규표현식)

매치객체.group('그룹이름')

>>> m = re.match('(?P<func>[a-zA-Z_][a-zA-Z0-9_]+)\((?P<arg>\w+)\)',
'print(1234)')

>>> m.group('func')    # 그룹 이름으로 매칭된 문자열 출력
'print'
>>> m.group('arg')     # 그룹 이름으로 매칭된 문자열 출력
'1234'



👉 패턴에 매칭되는 모든 문자열 가져오기

findall 함수로 매칭된 문자열을 리스트로 반환하면 그룹 지정 없이 패턴에 매칭되는 모든 문자열을 가져올 수 있다.

re.findall('패턴', '문자열')

# 문자열에서 숫자만 가져오기
>>> re.findall('[0-9]+', '1 2 Fizz 4 Buzz Fizz 7 8')
['1', '2', '4', '7', '8'] 



👉 문자열 바꾸기

sub 함수를 사용하며 패턴, 바꿀 문자열, 문자열, 바꿀 횟수를 넣어준다.
바꿀 횟수를 생략하면 찾은 문자열을 모두 바꾼다.

re.sub('패턴', '바꿀문자열', '문자열', 바꿀횟수)

>>> re.sub('apple|orange', 'fruit', 'apple box orange tree')    
# apple 또는 orange를 fruit로 바꿈
'fruit box fruit tree'
  • 바꿀 문자열 대신 교체 함수를 지정할 수도 있다. 교체 함수는 매개변수로 매치 객체를 받으며 바꿀 결과를 문자열로 반환하면 된다.
    교체함수(매치객체)
    re.sub('패턴', 교체함수, '문자열', 바꿀횟수)
    >>> def multiple10(m):        # 매개변수로 매치 객체를 받음
    ...     n = int(m.group())    # 매칭된 문자열을 가져와서 정수로 변환
    ...     return str(n * 10)    # 숫자에 10을 곱한 뒤 문자열로 변환해서 반환
    ...
    >>> re.sub('[0-9]+', multiple10, '1 2 Fizz 4 Buzz Fizz 7 8')
    '10 20 Fizz 40 Buzz Fizz 70 80'
    
    # 교체 함수의 내용이 간단하다면 다음과 같이 람다 표현식을 넣어도 됨
    >>> re.sub('[0-9]+', lambda m: str(int(m.group()) * 10), '1 2 Fizz 4 Buzz Fizz 7 8')
    '10 20 Fizz 40 Buzz Fizz 70 80'



👉 찾은 문자열을 결과에 다시 사용하기

정규표현식을 그룹으로 묶고, 바꿀 문자열에서 \숫자 형식으로 매칭된 문자열을 가져와서 사용할 수 있다.

>>> re.sub('([a-z]+) ([0-9]+)', '\\2 \\1 \\2 \\1', 'hello 1234')    
# 그룹 2, 1, 2, 1 순으로 바꿈
'1234 hello 1234 hello'
  • 그룹에 이름을 지어 \g<이름> 형식으로 매칭된 문자열을 가져올 수 있다. \g<숫자> 형식으로 숫자를 지정해도 된다.
    >>> re.sub('({\s*)"(?P<key>\w+)":\s*"(?P<value>\w+)"(\s*})', '<\\g<key>>\\g<value></\\g<key>>', '{ "name": "james" }')
    '<name>james</name>'




출처, 강의
💡 43.1 ~
💡 43.4

0개의 댓글