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
'programing' 카테고리의 다른 글
| 변수가 있지만 "INTO"가 없는 단순 "SELECT" (0) | 2023.07.30 |
|---|---|
| 파이썬에서 두 개의 목록을 사전으로 결합하려면 어떻게 해야 합니까? (0) | 2023.07.30 |
| PyDev "Import에서 정의되지 않은 변수" 오류를 해결하려면 어떻게 해야 합니까? (0) | 2023.07.30 |
| mysql 날짜에서 연도 변경 (0) | 2023.07.30 |
| ASP 이동 중.NET 아이덴티티 모델에서 클래스 라이브러리 (0) | 2023.07.30 |