programing

Python에서 문자열의 이스케이프 시퀀스 처리

mailnote 2023. 7. 30. 18:01
반응형

Python에서 문자열의 이스케이프 시퀀스 처리

때때로 파일이나 사용자로부터 입력을 받으면 이스케이프 시퀀스가 포함된 문자열이 나타납니다.저는 파이썬이 문자열 리터럴의 이스케이프 시퀀스를 처리하는 것과 같은 방식으로 이스케이프 시퀀스를 처리하고 싶습니다.

를 들어를들어들, 예를어예,,myString다음과 같이 정의됩니다.

>>> myString = "spam\\neggs"
>>> print(myString)
spam\neggs

나는 기능을 원합니다 (나는 그것을 부를 것입니다).process) 다음 작업을 수행합니다.

>>> print(process(myString))
spam
eggs

함수가 Python(위 링크의 표에 나열됨)에서 모든 이스케이프 시퀀스를 처리할 수 있는 것이 중요합니다.

파이썬이 이를 수행하는 기능이 있습니까?

올바른 방법은 'string-escape' 코드를 사용하여 문자열을 디코딩하는 것입니다.

>>> myString = "spam\\neggs"
>>> decoded_string = bytes(myString, "utf-8").decode("unicode_escape") # python3 
>>> decoded_string = myString.decode('string_escape') # python2
>>> print(decoded_string)
spam
eggs

AST 또는 eval을 사용하지 마십시오.문자열 코덱을 사용하는 것이 훨씬 안전합니다.

unicode_escape일반적으로 작동하지 않습니다.

밝혀진 바에 따르면string_escape또는unicode_escape솔루션은 일반적으로 작동하지 않습니다. 특히 실제 유니코드가 있는 경우에는 작동하지 않습니다.

만약 당신이 ASC가 아닌 모든 사람들이II 문자는 이스케이프됩니다(그리고 처음 128자를 초과하는 모든 문자는 ASCII가 아닙니다).unicode_escape당신을 위해 옳은 일을 할 것입니다. 문자 그대로 ASC가 아닌 ASC가 ,이미 당신의 문자열에 있는 캐릭터들은 일이 잘못될 것입니다.

unicode_escape기본적으로 바이트를 유니코드 텍스트로 변환하도록 설계되었습니다.그러나 파이썬 소스 코드와 같은 많은 곳에서 소스 데이터는 이미 유니코드 텍스트입니다.

이 작업이 올바르게 수행되는 유일한 방법은 먼저 텍스트를 바이트로 인코딩하는 것입니다.UTF-8은 모든 텍스트에 대한 합리적인 인코딩이므로, 작동해야 합니다, 그렇죠?

다음 예제는 Python 3에 있으므로 문자열 리터럴이 더 깨끗하지만 Python 2와 3 모두에서 약간 다른 표현으로 동일한 문제가 있습니다.

>>> s = 'naïve \\t test'
>>> print(s.encode('utf-8').decode('unicode_escape'))
naïve   test

음, 그건 틀렸습니다.

텍스트를 텍스트로 디코딩하는 코덱을 사용하는 새로운 권장 방법은 다음과 같습니다.codecs.decode 도움이 도움이 되셨어요?

>>> import codecs
>>> print(codecs.decode(s, 'unicode_escape'))
naïve   test

전혀 없습니다. (또한 위는 파이썬 2의 유니코드 오류입니다.)

unicode_escape 모든 비 ASC가 ASC가 아닌 것으로 하는 것으로 .II 바이트는 Latin-1(ISO-8859-1) 인코딩입니다.따라서 다음과 같이 작업해야 합니다.

>>> print(s.encode('latin-1').decode('unicode_escape'))
naïve    test

하지만 그건 끔찍해요.이것은 마치 유니코드가 전혀 발명되지 않은 것처럼 당신을 256개의 라틴-1 문자로 제한합니다.

>>> print('Ernő \\t Rubik'.encode('latin-1').decode('unicode_escape'))
UnicodeEncodeError: 'latin-1' codec can't encode character '\u0151'
in position 3: ordinal not in range(256)

문제 해결을 위한 정규식 추가

(놀랍게도, 우리는 지금 두 가지 문제를 안고 있습니다.)

우리가 해야 할 일은 단지 그것을 적용하는 것입니다.unicode_escape우리가 ASCII 텍스트라고 확신하는 것들에 대한 디코더.특히 ASCII 텍스트가 보장되는 유효한 Python 이스케이프 시퀀스에만 적용할 수 있습니다.

re.sub탈출할 수 없는 가치로 대체하는 것입니다.

import re
import codecs

ESCAPE_SEQUENCE_RE = re.compile(r'''
    ( \\U........      # 8-digit hex escapes
    | \\u....          # 4-digit hex escapes
    | \\x..            # 2-digit hex escapes
    | \\[0-7]{1,3}     # Octal escapes
    | \\N\{[^}]+\}     # Unicode characters by name
    | \\[\\'"abfnrtv]  # Single-character escapes
    )''', re.UNICODE | re.VERBOSE)

def decode_escapes(s):
    def decode_match(match):
        return codecs.decode(match.group(0), 'unicode-escape')

    return ESCAPE_SEQUENCE_RE.sub(decode_match, s)

그리고 그것으로:

>>> print(decode_escapes('Ernő \\t Rubik'))
Ernő     Rubik

python 3에 대한 정확하고 편리한 답변:

>>> import codecs
>>> myString = "spam\\neggs"
>>> print(codecs.escape_decode(bytes(myString, "utf-8"))[0].decode("utf-8"))
spam
eggs
>>> myString = "naïve \\t test"
>>> print(codecs.escape_decode(bytes(myString, "utf-8"))[0].decode("utf-8"))
naïve    test

『 』 『 』에 대한 내용codecs.escape_decode:

  • codecs.escape_decode 대 디코더입니다.
  • codecs.escape_decode다음과 시퀀스를 b"\\n"->b"\n",b"\\xce"->b"\xce".
  • codecs.escape_decode바이트 개체의 인코딩에 대해 관심이 없거나 알 필요가 없지만 이스케이프된 바이트의 인코딩은 나머지 개체의 인코딩과 일치해야 합니다.

배경:

  • @rspeer가 맞습니다.unicode_escapepython3에 대한 잘못된 솔루션입니다.는 는이유 때문입니다.unicode_escape이스케이프된 바이트를 디코딩한 다음 바이트를 유니코드 문자열로 디코딩하지만 두 번째 작업에 사용할 코덱에 대한 정보를 수신하지 않습니다.
  • @Jerub이 맞습니다. AST 또는 평가를 피하십시오.
  • 에 처음발것은을 발견했습니다.codecs.escape_decode답변에서 "Python3에서 I.decode('string-escape')를 어떻게 합니까?"로.그 대답이 말해주듯이, 그 함수는 현재 python 3에 대해 문서화되어 있지 않습니다.

함수가 근접하지만 문자열이 먼저 적절하게 따옴표로 묶일 것으로 예상됩니다.

에 대한따옴표로 묶는 .""r""u""따옴표 세 를 따 개 옴 표 적 입 따 로 표 옴 묶 다 니 있 습 로 수 할 전 으 달 다 음 고 등 의 한 절 을 력 사 용 자 사 하 여 용 ▁to , ▁input ▁so ▁triple ▁want ▁to ▁quotes 다 ▁you ) ▁may ▁wrap ▁in ▁etc ▁and 니 ▁the ▁quotes 습 있literal_eval따옴표로 묶으면 또한 방지됩니다.literal_eval숫자, 튜플, 사전 등을 반환하는 것으로부터.

사용자가 따옴표로 묶지 않은 문자열 형식의 따옴표를 입력할 경우에도 문제가 발생할 수 있습니다.

Jerub이 (현재) 수락한 답변은 python2에 대해서는 옳지만 올바르지 않으며 python3에 대해서는 (Apalala가 그 솔루션에 대한 코멘트에서 지적했듯이) 왜곡된 결과를 생성할 수 있습니다.unicode_escape 코덱은 공식 python 문서에 따라 소스를 utf-8이 아닌 latin-1로 코딩해야 하기 때문입니다.따라서 python3에서는 다음을 사용합니다.

>>> myString="špåm\\nëðþ\\x73"
>>> print(myString)
špåm\nëðþ\x73
>>> decoded_string = myString.encode('latin-1','backslashreplace').decode('unicode_escape')
>>> print(decoded_string)
špåm
ëðþs

이 방법은 또한 제럽의 솔루션에 대한 메타토스터의 코멘트에서 문자열과 바이트 사이의 불필요한 왕복을 방지합니다(그러나 해당 솔루션의 버그를 인식하기 위해 메타토스터에 모자를 씌웁니다).

이것은 나쁜 방법이지만, 문자열 인수에서 전달된 이스케이프 8진수를 해석하려고 할 때 효과가 있었습니다.

input_string = eval('b"' + sys.argv[1] + '"')

eval과 ast.literal_eval 사이에는 차이가 있다는 것을 언급할 가치가 있습니다(eval이 훨씬 더 안전하지 않음).python의 eval() 대 ast.literal_eval() 사용을 참조하십시오.

동일한 Python 문자열 리터럴처럼 보이도록 문자열을 적절하게 따옴표로 묶은 다음ast.literal_eval이것은 안전하지만, 여러분이 예상하는 것보다 훨씬 더 쉽게 맞출 수 있습니다.

쉽게 추가할 수 있습니다."끈의 시작과 끝까지, 하지만 우리는 또한 어떤 것도 확실히 해야 합니다."문자열 내부가 제대로 탈출되었습니다.Python과 완전히 호환되는 변환을 원한다면 잘못된 이스케이프 시퀀스의 사용되지 않는 동작을 고려해야 합니다.

백슬래시 하나를 다음에 추가해야 합니다.

  • 짝수 개의 백슬래시 시퀀스 뒤에 이중 괄호(필요한 경우 인용문을 이스케이프하지만 이미 이스케이프된 경우에는 백슬래시를 이스케이프하지 않고 인용문을 이스케이프하지 않도록 함); 및

  • 입력 끝에 있는 홀수 백슬래시의 시퀀스(그렇지 않으면 백슬래시가 우리를 둘러싸는 이중 슬롯을 벗어날 수 있기 때문).

다음은 여러 가지 어려운 사례를 보여주는 산성 테스트 입력입니다.

>>> text = r'''\\ \ \" \\" \\\" \'你好'\n\u062a\xff\N{LATIN SMALL LETTER A}"''' + '\\'
>>> text
'\\\\ \\ \\" \\\\" \\\\\\" \\\'你好\'\\n\\u062a\\xff\\N{LATIN SMALL LETTER A}"\\'
>>> print(text)
\\ \ \" \\" \\\" \'你好'\n\u062a\xff\N{LATIN SMALL LETTER A}"\

이 를 적절하게 표현식을 할 수 , 저는결이모적처정리게는하해수규, 했습니다용허고있었결할을식절국하건든을사▁i▁allowing▁properlyge다.literal_eval사용할 항목:

>>> def parse_escapes(text):
...     fixed_escapes = re.sub(r'(?<!\\)(\\\\)*("|\\$)', r'\\\1\2', text)
...     return ast.literal_eval(f'"{fixed_escapes}"')
... 

결과 테스트:

>>> parse_escapes(text)
'\\ \\ " \\" \\" \'你好\'\nتÿa"\\'
>>> print(parse_escapes(text))
\ \ " \" \" '你好'
تÿa"\

단일 따옴표와 이중 따옴표가 모두 포함된 문자열, 백슬래시가 포함된 모든 이상한 상황, ASC가 아닌 모든 것을 올바르게 처리해야 합니다.입력에 Ⅱ문자. (눈으로 결과를 확인하기가 좀 어렵다는 것은 인정합니다!)

문자열에 \n이 표시되도록 하려면 아래 코드가 작동해야 합니다.

import string

our_str = 'The String is \\n, \\n and \\n!'
new_str = string.replace(our_str, '/\\n', '/\n', 1)
print(new_str)

언급URL : https://stackoverflow.com/questions/4020539/process-escape-sequences-in-a-string-in-python

반응형