Python에서 RegEx 엔진을 빌드하는 방법(2.1부: Python 문자열)

소개



이전 에피소드 요약:
  • RegEx 엔진을 구축하려고 합니다.
  • 첫 번째 에피소드에서는 우리가 인식하고 싶은 문법에 대해 간략하게 이야기했습니다.
  • 두 번째 에피소드에서는 어휘 분석기를 만들었습니다(필요한 세 가지 구성 요소 중 첫 번째 구성 요소, 나머지 구성 요소는 파서, 마지막으로 엔진).

  • 이 에피소드는 RegEx 자체에 크게 집중하지 않고 프로젝트를 새로운 것을 배우기 위한 핑계로 사용하여 Python 문자열을 탐색할 것이기 때문에 일종의 스핀오프입니다.


    친애하는 파이썬



    아아아…파이썬 문자열…

    지금까지 만든 것의 문제는 Python의 문자열이 기본적으로 '\'를 이스케이프로 취급한다는 것입니다.

    따라서 우리의 구현에서 어휘 분석기는 '\'를 읽은 다음 그 다음 문자를 읽고 마지막으로 그 의미를 결정할 수 없습니다.

    예를 들어 어떤 이유로든 문자 'c'를 이스케이프하면 올바른 출력(char 필드 = 'c'가 있는 ElementToken)을 얻지만 이유가 잘못되었습니다. 그러나 이스케이프 문자 '\'를 '\'로 쓰면 예기치 않은 동작이 발생합니다.

    스캔한 토큰과 예상 토큰. b와 c 사이의 구멍은 '\t'이고 우리는 '\'를 원했습니다.


    스캔한 토큰과 예상 토큰. b와 c 사이의 구멍은 '\t'이고 우리는 '\'를 원했습니다.

    왜 이런 일이 발생합니까? 지금까지 수행한 Lexer 구현에 버그가 있습니까?

    대답은 '아니오'입니다. 구현에 버그가 없습니다.

    문제는 Python이 우리를 위해 이스케이프 문자를 이스케이프했기 때문에 어휘 분석기는 '\'를 하나의 문자, 백슬래시로 읽고 어휘 분석기는 다음 문자를 이스케이프 처리할 것입니다.

    그러나 이것은 우리가 원했던 동작이 아닙니다. 이스케이프된 백슬래시 뒤에 오는 문자가 아니라 백슬래시를 이스케이프 처리하고 싶었습니다.

    운 좋게도 이 동작을 '수정'하는 것은 어렵지 않으며 이를 수행할 수 있는 방법이 적어도 두 가지 있습니다.

    첫 번째 방법



    첫 번째 방법은 단순히 문자열 대신 원시 문자열을 어휘 분석기에 전달하는 것입니다. 이렇게 하려면 문자열 앞에 r을 붙이면 충분합니다.

    lexer.scan(r'ab\\tc')
    


    이렇게 하면 불행하게도 사용자는 필요할 때마다 문자열 대신 원시 문자열을 어휘 분석기에 전달해야 한다는 것을 기억해야 합니다.

    두 번째 방법



    첫 번째 솔루션의 문제점은 사용자가 이 특정 사항을 잊을 수 있고 그의 정규식이 예기치 않은 동작을 보일 수 있다는 것입니다.

    아마도 우리는 그것을 방지하고 자동으로 항상 문자열을 원시로 해석하여 이러한 이상한 동작이 발생하지 않도록 해야 합니다.

    이를 달성하려면 문자열 표현을 원시로 "변환"하는 함수를 작성하고 어휘 분석기가 처리를 수행하기 전에 즉시 호출해야 합니다.

    그렇게 하려면 다음과 같이 해야 합니다[1].

    def str_to_raw(s):
        raw_map = {8:r'\b', 7:r'\a', 12:r'\f', 10:r'\n', 13:r'\r', 9:r'\t', 11:r'\v'}
        return r''.join(i if ord(i) > 32 else raw_map.get(ord(i), i) for i in s)
    


    이러한 방식으로 전달된 정규식은 원시 문자열로 "변환"되고 원시로 해석됩니다.

    이 접근 방식의 문제점은 가능한 모든 이스케이프 시퀀스를 포함하도록 raw_map을 확장해야 하므로 매우 해키하다는 것입니다.

    이 솔루션은 특정 Python 구현에 매우 구체적이며 일반적으로 가능할 때마다 피해야 합니다.

    결론



    첫 번째 솔루션은 두 번째 솔루션이 얼마나 해킹되어 있는지 때문에 원하는 솔루션일 가능성이 높지만 원하는 솔루션을 구현하거나 직접 더 나은 솔루션을 찾을 수 있습니다.


    자원



    [1] How to create raw string from string variable in python? - 스택 오버플로 - 스택 오버플로


    Pankaj PatelUnsplash으로 표지하십시오.

    좋은 웹페이지 즐겨찾기