프로그래밍 정규식
정규효현식, 컴파일옵션, RawString
result = 0
for n in range(1, 1000):
if n%3==0 or n%5==0:
result += n
print(result)
space_content = tab_content.replace("\t", " "*4)
f = open(dst, 'w')
f.write(space_content)
f.close()
(288~291p)
(292~293p) 문제풀이 (반복 문자열 표시, defaultdict 같은 패키지 사용없이 풀어보기)
def compress_string(s):
_c = ""
cnt = 0
result = ""
for c in s:
if c!=_c:
_c = c
if cnt: result += str(cnt)
result += c
cnt = 1
else:
cnt +=1
if cnt: result += str(snt)
return result
print(compress_string("aaabbbcccccca")) # a3b2c6a1 출력
파이썬에서 정규표현식을 사용하려면 import re를 해야함.
1.전체 텍스트를 공백 문자로 나눈다(split)
2.나누어진 단어들이 주민등록번호 형식인지 조사한다.
3.단어가 주민등록번호 형식이라면 뒷자리를 '*'로 변환한다.
4.나누어진 단어들을 다시 조립한다.
data = """
park 800905-1049118
kim 700905-1059119
"""
result = []
for line in data.split("\n"):
word_result = []
for word in line.split(" "): # 공백 문자마다 나누기
if len(word) == 14 and word[:6].isdigit() and word[7:].isdigit():
word = word[:6] + "-" + "*******"
word_result.append(word)
result.append(" ".join(word_result)) # 나눈 단어 조립하기
print("\n".join(result))
# 결과값
park 800905-*******
kim 700905-*******
import re
data = """
park 800905-1049118
kim 700905-1059119
"""
pat = re.compile("(\d{6})[-]\d{7}")
print(pat.sub("\g<1>-*******", data))
# 결과값
park 800905-*******
kim 700905-*******
. ^ $ * + ? {} [] \ | ()
- [] 안의 두 문자 사이에 하이폰(-)을 사용하게 되면 두 문자 사이의 범위(From - To)를 의미한다
[a-c] = [abc] , [0-5] = [012345]
- 문자 클래스 내에서 ^ 메타 문자가 사용될 경우에는 반대(not)라는 의미를 갖는다.
[^0-9]라는 정규 표현식은 숫자가 아닌 문자만 매치된다.
- [a-zA-Z] : 알파벳 모두
- [0-9] : 숫자 모두
- 자주 사용하는 문자 클래스
\d : 숫자와 매치, [0-9]와 동일한 표현식이다.
\D : 숫자가 아닌 것과 매치, [^0-9]와 동일한 표현식이다.
\s : whitespace 문자와 매치, [ \t\n\r\f\v]와 동일한 표현식이다. 맨 앞의 빈 칸은 공백문자(space)를 의미한다.
\S : whitespace 문자가 아닌 것과 매치, [^ \t\n\r\f\v]와 동일한 표현식이다.
\w : 문자+숫자(alphanemeric)와 매치, [a-zA-Z0-9]와 동일한 표현식이다
\W : 문자+숫자(alphanemeric)가 아닌 문자와 매치, [^a-zA-Z0-9]와 동일한 표현식이다
4.Dot(.)
- 정규표현식의 Dot(.) 메타 문자는 줄바꿈 문자인 \n를 제외한 모든 문자와 매치됨을 의미한다.
a.b # a 와 b 사이에 줄바꿈 문자를 제외한 어떤 문자가 들어가도 모두 매치
"a + 모든 문자 + b" 와 같다. a와 b라는 문자 사이에 어떤 문자가 들어가도 모두 매치된다는 의미이다.
a[.]b # a 와 b 사이에 Dot(.) 문자가 있으면 매치
"a.b"라는 문자열과 매치, "a0b"라는 문자열과는 매치되지 않는다.
5.반복(*)
ca*t # * 문자 바로 앞에 있는 a가 0번이상 반복되면 매치
5-1. 반복(+)
ca+t # + 문자 바로 앞에 있는 a가 1번이상 반복되면 매치
5-2. 반복({m,n}, ?)
1) {m}ca{2}t # a가 2번 반복되면 매치
2) {m, n}
ca{2,5}t # a가 2번~5번 반복되면 매치
3) ? / ? 메타 문자가 의미하는 것은 {0,1}이다.
ab?c # b가 0번~1번 사용되면 매치 = b가 있어도 되고 없어도 된다
import re p = re.compile('ab*')
re.compile의 결과로 리턴되는 객체 p(컴파일 된 패턴 객체)를 이용하여 그 이후의 작업을 수행 가능
컴파일된 패턴 객체는 다음과 같은 4가지 메소드는 제공한다.
- match() : 문자열의 처음부터 정규식과 매치되는지 조사한다.
- search() : 문자열 전체를 검색하여 정규식과 매치되는지 조사한다.
- findall() : 정규식과 매치되는 모든 문자열(substring)을 리스트로 리턴한다.
- finditer() : 정규식과 매치되는 모든 문자열(substring)을 반복 가능한 객체로 리턴한다.
match,search는 정규식과 매치될 때는 match 객체를 리턴하고, 매치되지 않을 때는 None을 리턴한다.
group() : 매치된 문자열을 리턴한다.
start() : 매치된 문자열의 시작 위치를 리턴한다.
end() : 매치된 문자열의 끝 위치를 리턴한다.
span() : 매치된 문자열의 (시작,끝)에 해당되는 튜플을 리턴한다.
끝 인덱스의 위치는 +1해서 알려주는듯 (end()메소드의 경우 총 길이수가 나온다)
옵션명 약어 설명
DOTALL S 줄바꿈 문자를 포함하여 모든 문자와 매치할 수 있도록 한다.
IGNORECASE I 대,소문자에 관계 없이 매치할 수 있도록 한다.
MULTILINE M 여러 줄과 매치할 수 있도록 한다.(^,$ 메타 문자의 사용과 관계가 있는 옵션)
VERBOSE X verbose 모드를 사용할 수 있도록 한다.
(정규식을 보기 편하게 만들 수도 있고 주석 등을 사용할 수도 있다()
옵션을 사용할 때는 re.DOTALL처럼 전체 옵션명을 써도 되고, re.S처럼 약어를 써도 된다.
# 옵션 미사용 시 줄바꿈 \n은 포함하지않아 None값을 리턴
import re
p = re.compile('a.b')
m = p.match('a\nb')
print(m)
# 결과 >>> None
# 옵션 DOTALL 사용 시 줄바꿈 \n을 포함 가능
import re
p = re.compile('a.b', re.DOTALL)
m = p.match('a\nb')
print(m)
# 결과 >>> <_ser.SRE_Match object at 0x01FCF3D8>
p = re.compile('[a-z'], re.I) # re.I 옵션에 의해 대,소문자 구분없이 매치된다.
p.match('python')
# 결과 <_sre.SRE_Match object at 0x01FCFA30>
p.match('Python')
# 결과 <_sre.SRE_Match object at 0x01FCFA68>
p.match('PYTHON')
# 결과 <_sre.SRE_Match object at 0x01FCF9F8>
import re
p = re.compile("^python\s\w+")
data = """python one
life is too short
python two
you need python
python three"""
print(p.findall(data))
# 결과값 ['python one']
^ 메타 문자에 의해 python 이라는 문자열이 사용된 첫번째 라인만 매치가 된 것이다.
하지만 ^ 메타 문자를 문자열 전체의 처음이 아니라 각 라인의 처음으로 인식시키고 싶은 경우에 re.MULTILINE 또는 re.M을 쓰면 된다.
import re
p = re.compile("^python\s\w+", re.MULTILINE)
data = """python one
life is too short
python two
you need python
python three"""
print(p.findall(data))
# 결과값 ['python one', 'python two', 'python three']
즉, re.MULTILINE 옵션은 ^,$ 메타문자를 문자열의 각 라인마다 적용해 주는 것이다.
charref = re.compile(r'&[#](0[0-7]+|[0-9]+|x[0-9a-fA-F]+);')
charref = re.compilr(r"""
&[#] #Start of a numeric entity reference
(
0[0-7]+ #Octal form
|[0-9]+ #Decimal form
|x[0-9a-fA-F]+ #Hexadecimal form
)
; #Trailin semicolon
""", re.VERBOSE)
"\section" 이라는 문자열을 찾기위한 정규식을 만든다 할 때
\s 가 whitespace로 해석되어 매치가 이상하게 된다.
\section
은 아래와 동일한 의미이다.
[\t\n\r\f\v]ection # \s 문자가 이스케이프 코드 \t,\n,\r,\f,\v로 해석됨
의도한대로 매칭을 하고 싶다면 다음과 같이 변경해야 한다.
\\section
즉, 위 정규식에서 사용한 \ 문자가 문자열 그 자체임을 알려주기 위해 \ 2개를 사용하여 이스케이프 처리를 해야하는 것이다.
따라서 위 정규식을 컴파일 하려면 다음과 같이 작성해야한다.
p = re.compile('\\section')
정규식 엔진에 \ 문자 2개를 전달하려면 아래처럼 백슬래시 4개를 써야한다.
p = re.compile('\\\\section')
그래서 파이썬 정규식에는 Raw String이라는 규칙이 생겨났다.
컴파일 해야하는 정규식이 Raw String임을 알려주는 문법이다.p = re.compile(r'\\section')
위와 같이 정규식 문자열 앞에 r 문자를 삽입하면 이 정규식은 Raw String 규칙에 의하여
백슬래시 2개 대신 1개만 써도 2개를 쓴 것과 동일한 의미를 갖게 된다.