# 정규 표현식 : 복잡한 문자열을 처리할때 사용하는 기법, "모든 언어 공통"
# https://wikidocs.net/1642

'''
# 정규 표현식은 왜 필요한가?
# 주민등록번호를 포함하고 있는 텍스트가 있다. 이 텍스트에 포함된 모든 주민등록번호의 뒷자리를 * 문자로 변경해 보자.

# 우선 정규식을 전혀 모르면 다음과 같은 순서로 프로그램을 작성해야 할 것이다.

# [1] 전체 텍스트를 공백 문자로 나눈다(split).
# [2] 나뉜 단어가 주민등록번호 형식인지 조사한다.
# [3] 단어가 주민등록번호 형식이라면 뒷자리를 *로 변환한다.
# [4] 나뉜 단어를 다시 조립한다.
# [5] 이를 구현한 코드는 아마도 다음과 같을 것이다.

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))

# 반면에 정규식을 사용하면 다음처럼 훨씬 간편하고 직관적인 코드를 작성할 수 있다. 

import re 

data = """
park 800905-1049118
kim  700905-1059119
"""

pat = re.compile("(\d{6})[-]\d{7}")
print(pat.sub("\g<1>-*******", data))

# 정규 표현식을 사용하면 이렇게 간단한 예제에서도 코드가 상당히 간결해진다. 
# 만약 찾으려는 문자열 또는 바꾸어야 할 문자열의 규칙이 매우 복잡하다면 정규식의 효용은 더 커지게 된다.
'''


# 정규 표현식 시작하기
'''
# 수식

# 문자클래스 []
# [abc]

# []사이의 문자들과 매치
# "a"는 정규식과 일치하는 문자인 "a"가 있으므로 매치
# "before"는 정규식과 일치하는 문자인 "b"가 있으므로 매치
# "dude"는 정규식과 일치하는 문자인 "a","b","c"중 어느 하나도 포함하고 있지 않으므로 매치되지 않음
# 하이픈을 사용하여 From-To로 표현 가능 (ex : [a-c]=[abc], [0,5]=[012345])


# [Dot(.)]
# a.b

# 줄바꿈(\n)을 제외한 모든 문자와 매치
# "aab"는 가운데 문자 "a"가 모든 문자를 의미하는 '.'과 일치하므로 정규식과 매치
# "a0b"는 가운데 문자 "0"가 모든 문자를 의미하는 '.'과 일치하므로 정규식과 매치
# "abc"는 "a"문자와 "b"문자 사이에 어떤 문자라도 하나는 있어야 하는 이 정규식과 일치하지 않으므로 매치되지 않는다.


# 반복(*)
# ca*t

# "ct"는 "a"가 0번 반복되어 매치 (0번 반복되어도 매치가 된다.)
# "cat"는 "a"가 0번 이상 반복되어 매치 (1번 반복)
# "caaat"는 "a"가 0번 이상 반복되어 매치 (3번 반복)


# 반복(+)
# ca+t

# "ct"는 "a"가 0번 반복되어 매치되지 않음
# "cat"는 "a"가 0번 이상 반복되어 매치 (1번 반복)
# "caaat"는 "a"가 0번 이상 반복되어 매치 (3번 반복)


# 반복({m,n},?)
# ca{2}t : a가 딱 2번 / 즉, aa일 경우만 매치

# "cat"는 "a"가 1번만 반복되어 매치되지 않음
# "caat"는 "a"가 2번 반복되어 매치


# 반복({m,n},?)
# ca{2,5}t : a가 딱 2번 이상, 5번 이하일 경우 매치 / 2~5

# "cat"는 "a"가 1번만 반복되어 매치되지 않음
# "caat"는 "a"가 2번 반복되어 매치
# "caaaaat"는 "a"가 5번 반복되어 매치


# 반복({m,n},?)
#ab?c : ? == {0,1}와 같은 표현 / ?가 0번 혹은 1번이 사용되어야 매치

# "abc"는 "b"가 1번만 사용되어 매치
# "ac"는 "b"가 0번 사용되어 매치
'''
'''
# 파이썬에서 정규 표현식을 지원하는 re모듈

# [match : 문자열의 처음부터 정규식과 매치되는지 조사한다.]
import re # re를 이용하여 정규 표현식을 사용하겠다.

# p = re.compile('[a-z]+') # a~z까지 1번이상 반복되는 표현을 찾음
# # m = p.match("python") # "python" 문자열은 [a-z]+ 정규식에 부합되므로 match 객체를 돌려준다.
# m = p.match('3 python') # "3 python" 문자열은 처음에 나오는 문자 3이 정규식 [a-z]+에 부합되지 않으므로 None을 돌려준다.
# print(m)

# match의 결과로 match 객체 또는 None을 돌려주기 때문에 파이썬 정규식 프로그램은 보통 다음과 같은 흐름으로 작성한다.
p = re.compile('[a-z]+') # (정규표현식)
m = p.match('string goes here')
if m:
    print('Match found: ', m.group())
else:
    print('No match')
'''
'''
# [search : 문자열 전체를 검색하여 정규식과 매치되는지 조사한다.]
import re # re를 이용하여 정규 표현식을 사용하겠다.
p = re.compile('[a-z]+') # a~z까지 1번이상 반복되는 표현을 찾음
m = p.search('3 python') # "3 python" 문자열의 첫 번째 문자는 "3"이지만 search는 문자열의 처음부터 검색하는 것이 아니라 문자열 전체를 검색하기 때문에 "3" 이후의 "python" 문자열과 매치된다.
print(m)

# 이렇듯 match 메서드와 search 메서드는 문자열의 처음부터 검색할지의 여부에 따라 다르게 사용해야 한다.
'''

'''
# [findall : 정규식과 매치되는 모든 문자열(substring)을 리스트로 돌려준다.]
import re # re를 이용하여 정규 표현식을 사용하겠다.
p = re.compile('[a-z]+') # a~z까지 1번이상 반복되는 표현을 찾음
m = p.findall('list is too short') # "life is too short" 문자열의 'life', 'is', 'too', 'short' 단어를 각각 [a-z]+ 정규식과 매치해서 리스트로 돌려준다.
print(m)
'''
'''
# [finditer : 정규식과 매치되는 모든 문자열(substring)을 반복 가능한 객체로 돌려준다.]
import re # re를 이용하여 정규 표현식을 사용하겠다.
p = re.compile('[a-z]+') # a~z까지 1번이상 반복되는 표현을 찾음
m = p.finditer('list is too short') # 첫 단어에 a-z까지의 수만 있는게 아닐경우 매치가 되지 않음
for r in m:
    print(r) # finditer는 findall과 동일하지만 그 결과로 반복 가능한 객체(iterator object)를 돌려준다. 반복 가능한 객체가 포함하는 각각의 요소는 match 객체이다.
# print(m)
'''
