ABOUT ME

-

Total
-
  • #1 파이썬 정규 표현식 공부 (regular expression)
    컴퓨터/파이썬 2020. 5. 11. 22:33
    728x90
    반응형
    string 의미
    \d 숫자 [0-9]
    \D 숫자 아닌 것 [^0-9]
    \s [ \t\n\r\f\v ]
    \S [^\s]
    \w 문자+숫자
    [a-zA-Z0-9]
    \W [^\w]
    [ ] 문자 클래스
    . \n 제외한 모든 문자 매치
    (a.b = a+모든+b)
    * 반복 : 0번 이상 무한 반복
    (a*b = a + a*N + b)
    + 반복 : 1번 이상 무한 반복
    (a+b = a + a*N + b)
    {m,n} 반복 : m~n번 반복
    (a{2}b = a + aa + b)
    {,2} = 0~2
    {2, } = 2~무한
    ? 반복 : {0, 1} 의미
    (a?b = a + a(없어도 됨) + b)
    ?P 하위 표현식 이름 붙히는 법
    (?P<name>\w{3})
    \g 하위 표현식 group
    a.sub("(\g<name>)", data)

     

    ( 식 ) 하위 표현식에 넣는 방법 -> sub(\g<1>, g<2>) 식으로 사용 가능 (lambda x: x.group(n))

    (19|20)\d{2} = 19xx or 20xx 문자를 캐치하는 법

    \<H([1-5])\>.*?\<\/H\1\> = <H1></H1>과 같이 시작태그=끝태그 알맞게 끝났는지 체크

    ( 1~5까지를 하위표현식에 넣어, 각각 매치되는 태그로 끝내기. \1)

     

    1. 주민번호 뒷자리 가리기

    ※ (\d{6})[-]\d{7} = 6자리-7자리, 앞자리를 유지하기 위해, (하위 표현식)에 넣음

    import re
    
    # 주민번호 뒷자리 가리기
    data = """
    KUN : 800905-1049118
    SON : 700905-1059119
    KIM : 900905-2323222
    """
    
    pat = re.compile("(\d{6})[-]\d{7}")
    print(pat.sub("\g<1>-" + "*" * 7, data))
    # KUN : 800905-******* ...

    2. 전화번호 가리기

    ※ (?P<head>\d{3})-(\d{4})-(\d{4}) = 3개의 하위 표현식, 맨 앞자리를 head로 하위 표현식 이름을 지었음

    import re
    
    # (010)-XXXX-XXXX 로 바꾸기
    data = """
    SEEK = 010-1234-5890
    TEST = 010-4414-5142
    TETT = 011-2421-1242
    """
    
    pat = re.compile("(?P<head>\d{3})-(\d{4})-(\d{4})")
    print(pat.sub("(\g<head>)-\g<2>-\g<3>", data))
    # SEEK = (010)-1234-5890 ...

    3. <H></H> 태그 안 문자 대문자화

    \<H[1-5]\>(.*?)\<\/H[1-5]\> = 1개의 하위 표현식, <H></H> 안 문자만 대문자화

    lambda 식을 사용해서 (.*?) 매치되는 문자 모두 대문자화, ("\g<1>".upper()은 작동 안 됨)

    import re
    
    # H태그 안 문자들을 모두 대문자화 하기
    data = """
    <BODY>
    <H1>Welcome</H1>
    <p>this is p tag<></p>
    <H2>AbCCddeFGH</H2>
    <H3>test Word for</H3>
    <H4>la casa de papel</H3>
    <H5>svip coupon</H5>
    I have no tag, lonely
    </BODY>
    """
    
    pat = re.compile("\<H[1-5]\>(.*?)\<\/H[1-5]\>")
    print(pat.sub(lambda x: x.group(1).upper(), data))
    
    """ <h> 태그는 버린다
    <BODY>
    WELCOME
    <p>this is p tag<>/p>
    """
    

    4. 가장 긴 Palindrome regex로 찾기 

    \w + (.*) + \w = a ~ a 사이 글자(greedy)를 하위 표현식에 넣었음.

    pattern.group() 을 통해 하위 표현식 불러옴 (re.search | TC = O(n))

    import re
    
    
    def findlongestPalindromicSubstring(string):
        stack = set()
    
        for i, str in enumerate(string):
            new_string = string[i:]
            pattern = re.search(str + "(.*)" + str, new_string)
            if pattern:
                if is_palindrome(pattern.group()):
                    print('pattern', pattern.group())
                    stack.add(pattern.group())
    
        return max(stack, key=len) if len(string) > 1 else string
    
    def is_palindrome(str):
        return str == str[::-1]
        
    str = "abaabsvssvsaczcxbzccaabaczcaaa"
    print(findlongestPalindromicSubstring(str))
    

     

    Regex Coach를 이용해서 바로바로 볼 수 있다.

    혹은 온라인에서 실시간 (https://regexr.com/)

     

    외전 : .* vs .*? (greedy vs Non-greedy)

    eeeAiiZuuuuAoooZeeee 이 문자열을 각각의 regex를 사용해보면

    A.*Z : AiiZuuuuAoooZ (1개만 매치) (끝까지 매칭되는 걸 찾음)

    A.*?Z : AiiZ , AoooZ (2개 매치) (중간에 매치되면 끊고, 다른 것 찾음)

     

    \<H([1-5])\>(.*?)\<\/H\1\> 에서

    <H1>TEXT</H1>DDE</H1> 처음부터 앞 </H1>까지만 받음

    (.*)으로 하면

    <H1>~~</H1>~~</H1> 끝까지 매칭 모두 포함

     

    http://sweeper.egloos.com/3064730

    https://wikidocs.net/1669

    728x90

    댓글