ファイルまたはユーザーから入力を取得すると、エスケープシーケンスを含む文字列を取得することがあります。エスケープシーケンスを処理したいと思います Python文字列リテラルのエスケープシーケンスを処理するのと同じ方法で 。
たとえば、myString
が次のように定義されているとします。
>>> myString = "spam\\neggs"
>>> print(myString)
spam\neggs
これを行う関数(process
と呼びます)が必要です。
>>> print(process(myString))
spam
eggs
関数がPython(上記のリンクの表に記載)のすべてのエスケープシーケンスを処理できることが重要です。
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
ソリューションは一般に機能しないことがわかりました。特に、実際のUnicodeが存在する場合は機能しません。
every非ASCII文字がエスケープされることが確実な場合(および、最初の128文字を超えるものは非ASCIIであることを忘れないでください)、unicode_escape
が正しいことを行います。ただし、文字列に非ASCII文字がリテラルとして含まれていると、問題が発生します。
unicode_escape
は、基本的にバイトをUnicodeテキストに変換するように設計されています。しかし、多くの場所(たとえば、Pythonソースコード)では、ソースデータは既にUnicodeテキストです。
これが正しく機能する唯一の方法は、最初にテキストをバイトにエンコードする場合です。 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
どういたしまして。 (また、上記はPython 2のUnicodeErrorです。)
unicode_escape
コーデックは、その名前にもかかわらず、すべての非ASCIIバイトがLatin-1(ISO-8859-1)エンコーディングであると想定していることがわかりました。したがって、次のようにする必要があります。
>>> print(s.encode('latin-1').decode('unicode_escape'))
naïve test
しかし、それはひどいです。これにより、Unicodeがまったく発明されたことがないかのように、256個のLatin-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)
(驚いたことに、今では2つの問題はありません。)
必要なのは、ASCIIテキストであることが確実なものにのみunicode_escape
デコーダーを適用することです。特に、Pythonテキストであることが保証されている有効なASCIIエスケープシーケンスにのみ適用することを確認できます。
計画では、正規表現を使用してエスケープシーケンスを見つけ、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"
などのASCIIエスケープシーケンスをデコードします。codecs.escape_decode
は、バイトオブジェクトのエンコードを気にする必要も、認識する必要もありませんが、エスケープされたバイトのエンコードは、オブジェクトの残りのエンコードと一致する必要があります。バックグラウンド:
unicode_escape
はpython3の不正解です。これは、unicode_escape
がエスケープされたバイトをデコードし、次にバイトをUnicode文字列にデコードするが、2番目の操作に使用するコーデックに関する情報を受け取らないためです。codecs.escape_decode
を から発見しました。「Python3で.decode( 'string-escape')を実行するにはどうすればよいですか?」 その答えが述べているように、その関数は現在python 3。ast.literal_eval
関数が近づきますが、文字列が最初に適切に引用されることが期待されます。
もちろん、バックスラッシュエスケープのPythonの解釈は、文字列の引用方法に依存します(""
vs r""
vs u""
、三重引用符など)を使用して、ユーザー入力を適切な引用符で囲み、literal_eval
。引用符で囲むと、literal_eval
数値、タプル、辞書などを返すことから.
ユーザーが文字列をラップしたいタイプの引用符で囲まれていない引用符を入力すると、物事は依然として厄介になるかもしれません。
これはそれを行うのに悪い方法ですが、文字列引数に渡されたエスケープされた8進数を解釈しようとすると、うまくいきました。
input_string = eval('b"' + sys.argv[1] + '"')
Evalとast.literal_evalには違いがあることに言及する価値があります(evalは安全性がはるかに低い)。 pythonのeval()とast.literal_eval()の使用を参照してください?
以下のコードは、文字列に表示するために\ nが必要です。
import string
our_str = 'The String is \\n, \\n and \\n!'
new_str = string.replace(our_str, '/\\n', '/\n', 1)
print(new_str)