Python( 정규식 )

짬그브·2025년 2월 25일

정규표현식

정규표현식이라는이름은정규문자열을식별하는데서유래되었다.

정규표현식은문자열이주어진규칙에일치하는지, 일치하지않는지판단할
수있다.

글자a를최소한한번쓰시오
그뒤에b를정확히다섯개쓰시오
그뒤에c를짝수번쓰시오
마지막에d가있어도되고없어도됩니다.
=> aaaabbbbbccccd, aabbbbbcc 등이성립한다.
aabbbbb(cc)(d|)

정규표현식

규칙1 : 이메일주소의첫번째부부에는다음중최소한하나가포함되어야합니다. 대
문자, 소문자, 숫자0-9, 마침표(.), 플러스기호(+), 밑줄기호
[A-Za-z0-9._+]+
규칙2:그다음에@가나타나야한다.
@
규칙3:그다음에는반드시대문자나소문자가최소한하나있어야한다.
[A-Za-z]+
규칙4: 그다음에는마침표가온다.
.
규칙5: 이메일주소는com, org, edu, net중하나로끝난다.
(com|org|edu|net)
[A-Za-z0-9._+]+@[A-Za-z]+.(com| org| edu| net)

정규표현식 사용하기

정규표현식(regular expression)은 일정한 규칙(패턴)을 가진 문자열을 표현하는 방법

복잡한 문자열 속에서 특정한 규칙으로 된 문자열을 검색한 뒤 추출하거나 바꿀 때 사용함

문자열이 정해진 규칙에 맞는지 판단할 때도 사용함

문자열 판단하기

정규표현식은 re 모듈을 가져와서 사용하며 match 함수에 정규표현식 패턴과 판단할 문자열을 넣음 (re 는 regular expression의 약자)

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

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

문자열 앞에 ^를 붙이면 문자열이 맨 앞에 오는지 판단하고, 문자열 뒤에 $를 붙이면 문자열이 맨 뒤에 오는지 판단함(특정 문자열로 끝나는지)

^문자열
문자열$

이때는 match 대신 search 함수를 사용해야함

match 함수는 문자열 처음부터 매칭되는지 판단하지만, search는 문자열 일부분이 매칭되는지 판단함

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

import re

rc = re.compile('world')
rdata1  = re.search(rc,'hello world it is good')
print(rdata1)
print(rdata1.span())
print(rdata1.group(0))
print(rdata1.group())

rdata1 = re.search(r'world','hello world it is good')
print(rdata1)
rdata1 = re.search('world','hello world it is good')
print(rdata1)
rdata1 = re.search('hello','hello world hello it is good')
print(rdata1)

rdata2 = re.match(r'hello', 'hello world hello it is good')
print(rdata2)
rdata2 = re.match(r'world', 'hello world hello it is good')
print(rdata2)
fdata1 = re.findall(r'hello', 'hello world hello it is good')
print(fdata1)

rdata3 = re.search(r'^hello','hello world hello it is good')
print(rdata3)
rdata3 = re.search(r'^world','hello world hello it is good')
print(rdata3)
rdata3 = re.search(r'good$','hello world hello it is good')
print(rdata3)
rdata3 = re.search(r'world$','hello world hello it is good')
print(rdata3)

결과값

<re.Match object; span=(6, 11), match='world'>
(6, 11)
world
world
<re.Match object; span=(6, 11), match='world'>
<re.Match object; span=(6, 11), match='world'>
<re.Match object; span=(0, 5), match='hello'>
<re.Match object; span=(0, 5), match='hello'>
None
['hello', 'hello']
<re.Match object; span=(0, 5), match='hello'>
None
<re.Match object; span=(24, 28), match='good'>
None

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

기본 개념은 OR 연산자와 같음

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

'hello|word'는 문자열에서 'hello' 또는 'world'가 포함되는지 판단함

fdata2 = re.findall(r'hello|world','hello world hello it is good')
print(fdata2)

결과값

['hello', 'world', 'hello']

범위 판단하기

다음과 같이 안에 숫자 범위를 넣으며 * 또는 +를 붙임

숫자 범위는 0-9처럼 표현하며 *는 문자(숫자) 가 0 개 이상 있는지, +는 1개 이상 있는지 판단함

fdata3 = re.findall(r'a*b','ab abb bb ccc')
print(fdata3)

fdata3 = re.findall(r'a+b','ab abb bb ccc aab aaa')
print(fdata3)

fdata3 = re.findall(r'a+b*','ab abb bb ccc aab aaa')
print(fdata3)

fdata4 = re.findall(r'[0-9]+','hello 3232 find fx855eee')
print(fdata4)

결과값

['ab', 'ab', 'b', 'b', 'b']
['ab', 'ab', 'aab']
['ab', 'abb', 'aab', 'aaa']
['3232', '855']

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

?와 . 을 사용함

?는 ? 앞의 문자(범위)가 0개 또는 1개인지 판단하고, .은 .이 있는 위치에 아무 문자(숫자) 가 1개 있는지 판단합니다.

문자?
[0-9]?
.

fdata5 = re.findall(r'b.d','bed bad bld b@d')
print(fdata5)

결과값

['bed', 'bad', 'bld', 'b@d']

문자 개수 판단하기

문자열의 경우에는 문자열을 괄호로 묶고 뒤에 {개수} 형식을 지정함

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

h{3}은 h 가 3 개 있는지 판단하고, (hello){3}은 hello 가 3개 있는지 판단함

특정 범위의 문자(숫자) 가 몇 개 있는지 판단할 수도 있음

이때는 범위 []뒤에 {개수} 형식을 지정함

[0-9]{개수}

이 기능은 문자(숫자)의 개수 범위도 지정할 수 있음

{시작개수,끝개수} 형식으로 시작 개수와 끝 개수를 지정해주면 특정 개수 사이에 들어가는지 판단함
(문자){시작개수,끝개수}
(문자열){시작개수,끝개수}
[0-9]{시작개수,끝개수}

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

영문 문자 범위는 a-z , A-z와 같이 표현함

한글은 영문 문자와 방법이 같음

가-힣 처럼 나올 수 있는 한글 조합을 정해주면 됨

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

특정 문자 범위에 포함되지 않는지 판단하려면 다음과 같이 문자(숫자) 범위 앞에 ^를 붙이면 해당 범위를 제외함

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

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

범위를 제외할 때는 '[^A-Z]+'와 같이 [] 안에 넣어주고, 특정 문자 범위로 시작할 때는 '^[A-Z]+'와 같이 [] 앞에 붙여줌

다음과 같이 '^[A-Z]+'는 영문 대문자로 시작하는지 판단함

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

특수 문자 판단하기

단순히 숫자인지 문자인지 판단할 때는 \d, \D, \w, \W를 사용하면 편리함

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

공백 처리하기

공백은 ''처럼 공백 문자를 넣어도 되고, \s 또는 \S 로 표현할 수도 있음

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

import re

fdata1 = re.findall(r'[0-9]{3}-[0-9]{4}-[0-9]{4}', 'tel:010-7878-8989 home')
print(fdata1)

fdata1 = re.findall(r'[0-9]{2,3}-[0-9]{3,4}-[0-9]{4}', 'tel:010-7878-8989 home:02-4546-7878 p:032-789-8989')
print(fdata1)

fdata2 = re.findall(r'[a-zA-Z]+', '232hello Good32 hi')
print(fdata2)

fdata2 = re.findall(r'[a-z0-9]+', '232hello Good32 hi')
print(fdata2)

fdata2 = re.findall(r'[가-힣]+', 'hello good안녕하세요121 반갑습니다.')
print(fdata2)

fdata2 = re.findall(r'[ㄱ-ㅎㅏ-ㅣ가-힣]+', 'helloㅋㅋㅋ itㅎㅎㅎ good안녕하세요121 반갑습니다.')
print(fdata2)

fdata3 = re.findall(r'[^A-Z]+', 'Hello GOOD morning 2323 안녕하세요')
print(fdata3)

fdata3 = re.findall(r'[^가-힣]+', 'Hello GOOD morning 2323 안녕하세요')
print(fdata3)

fdata4 = re.findall(r'\d{3}-\d{4}-\d{4}', 'tel:818-7878-8989 home')
print(fdata4)

fdata5 = re.findall(r'\D+', 'Hello GOOD morning 23232 안녕하세요')
print(fdata5)

fdata6 = re.findall(r'\w+','print_info323(hello_insa)')
print(fdata6)

fdata6 = re.findall(r'\W+','print_info323(hello_insa)')
print(fdata6)

fdata7 = re.findall(r'[a-zA-Z0-9]+', 'hhello tel: 02-7887-8989          ^^')
print(fdata7)

fdata7 = re.findall(r'[a-zA-Z0-9\s]+', 'hhello tel: 02-7887-8989          ^^')
print(fdata7)

fdata7 = re.findall(r'[a-zA-Z0-9\S]+', 'hhello tel: 02-7887-8989          ^^')
print(fdata7)

결과값

['010-7878-8989']
['010-7878-8989', '02-4546-7878', '032-789-8989']
['hello', 'Good', 'hi']
['232hello', 'ood32', 'hi']
['안녕하세요', '반갑습니다']
['ㅋㅋㅋ', 'ㅎㅎㅎ', '안녕하세요', '반갑습니다']
['ello ', ' morning 2323 안녕하세요']
['Hello GOOD morning 2323 ']
['818-7878-8989']
['Hello GOOD morning ', ' 안녕하세요']
['print_info323', 'hello_insa']
['(', ')']
['hhello', 'tel', '02', '7887', '8989']
['hhello tel', ' 02', '7887', '8989          ']
['hhello', 'tel:', '02-7887-8989', '^^']

그룹 사용하기

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

(정규표현식)(정규표현식)

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

매치객체.group(그룹숫자)

그룹 사용하기

매치객체.groups()

(?p<이름>정규표현식)

그룹 개수가 많아지면 숫자로 그룹을 구분하기가 힘들어짐

그룹에 이름을 지으면 편리함

import re

robj1 = re.search(r'([0-9]+)([0-9]+)', 'good 423 122 hello')
print(robj1)
print(robj1.group(0))
print(robj1.group(1))
print(robj1.group(2))
print(robj1.groups())

robj2 = re.search(r'(?P<func>[a-zA-Z_][a-zA-Z0-9_]+)\((?P<args>\w+)\)','hello _print_info(var22) good job')
print(robj2)
print(robj2.group(1))
print(robj2.group(2))
print(robj2.group('func'))
print(robj2.group('args'))

결과값

<re.Match object; span=(5, 8), match='423'>
423
42
3
('42', '3')
<re.Match object; span=(6, 24), match='_print_info(var22)'>
_print_info
var22
_print_info
var22

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

그룹 지정 엇이 패턴에 매칭되는 모든 문자열을 가져오려면 findall 함수를 사용하며 매칭된 문자열을 리스트로 반환함

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

문자열 바꾸기

문자열을 바꿀 때는 sub 함수를 사용하며 패턴, 바꿀 문자열, 문자열, 바꿀횟수를 넣어줌

바꿀 횟수를 넣으면 지정된 횟수만큼 바꾸며 바꿀 횟수를 생략하면 찾은 문자열을 모두 바꿈

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

sub 함수는 바꿀 문자열 대신 교체 함수를 지정할 수도 있음

교체 함수는 매개변수로 매치 객체를 받으며 바꿀 결과를 문자열로 반환하면 됨

교체함수(매치객체)
re.sub('패턴',교체함수,'문자열',바꿀횟수)

교체 함수의 내용이 간단하다면 람다 표현식을 만들어서 넣어도 됨

import re

cstr1 = re.sub(r'apple|orange','fruit','apple box orange box')
print(cstr1)

cstr2 = re.sub(r'나의|내','그의','나의 물건에 손대지 마시오')
print(cstr2)
print()

def multi10(m):
    n = int(m.group())
    return str(n * 10)

cstr3 = re.sub(r'[0-9]+',multi10,'function32 745 fruit:5')
print(cstr3)
print()

cstr4 = re.sub(r'([a-z]+) ([0-9]+)','\\2 \\1 \\2 \\1','hello good 4323 76')
print(cstr4)

cstr5 = re.sub(r'(\{\s*)\"(\w+)\"\:\s*\"(\w+)\"\s*\}', '<\\2>\\3<\\2>', '{"name": "kim"}')
print(cstr5)

결과값

fruit box fruit box
그의 물건에 손대지 마시오

function320 7450 fruit:50

hello 4323 good 4323 good 76
<name>kim<name>

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

\\숫자

정규표현식을 그룹으로 묶음

바꿀 문자열에서 \숫자 형식으로 매칭된 문자열을 가져와서 사용할 수 있음

import re

#greedy
fdata1 = re.findall(r'<b>.+</b>', '<b>blog</b> is a<b>website</b>containg a body')
print(fdata1)

#lazy
fdata1 = re.findall(r'<b>.+?</b>', '<b>blog</b> is a<b>website</b>containg a body')
print(fdata1)

결과값

['<b>blog</b> is a<b>website</b>']
['<b>blog</b>', '<b>website</b>']
profile
+AI to AI+

0개의 댓글