4

結論:生のプレフィックス指定子の使用をスキップできるように、Python の組み込みのエスケープ シーケンス処理をオーバーライドまたは無効にすることはできません。これを理解するために、Pythonの内部を掘り下げました。したがって、何らかのフレームワークの一部として複雑な文字列 (正規表現など) で動作するオブジェクトを設計しようとする場合は、オブジェクトの文字列引数に接頭辞を含める__init__() 必要があることを docstring で指定してください。r




元の質問:ユーザーが入力した文字列について何も「変更」しないように Python に強制するのは少し難しいと思います。これには、正規表現やエスケープされた 16 進シーケンスが含まれている可能性があります。生の文字列(およびそのデコード対応)のさまざまな組み合わせをすでに試しました.encode('string-escape')が、正しいアプローチが見つかりません。

ドキュメンテーション IPv6 アドレス のエスケープされた 16 進表現が与えられた場合2001:0db8:85a3:0000:0000:8a2e:0370:7334、 を使用して.encode()、この小さなスクリプト ( と呼ばれますx.py):

#!/usr/bin/env python

class foo(object):
    __slots__ = ("_bar",)
    def __init__(self, input):
        if input is not None:
            self._bar = input.encode('string-escape')
        else:
            self._bar = "qux?"

    def _get_bar(self): return self._bar
    bar = property(_get_bar)
#

x = foo("\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x8a\x2e\x03\x70\x73\x34")
print x.bar


実行すると、次の出力が生成されます。

$ ./x.py
 \x01\r\xb8\x85\xa3\x00\x00\x00\x00\x8a.\x03ps4


\x20が ASCII スペース文字に変換されていることに注意してください。これは、Python がエスケープされた 16 進シーケンスを処理し、それらを印刷可能な ASCII 値に変換するため、基本的に正しいです。


foo()次のように、イニシャライザが生の文字列として処理された場合 (および.encode()呼び出しが削除された場合)、これを解決できます。

x = foo(r"\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x8a\x2e\x03\x70\x73\x34")


ただし、私の最終目標は、使用できる一種のフレームワークを作成することであり、これらの種類の「実装の詳細」をエンドユーザーから隠したいと考えています。上記の IPv6 アドレスをエスケープされた 16 進形式 (生の指定子なし)で呼び出し、すぐにそれを出力した場合、生の指定子を知らずに、または使用せずに入力したものを正確foo()に返す必要があります。したがって、それを可能にするために必要な処理を に実行させる方法を見つける必要があります。foo__init__()



編集:この SO questionごとに、常にある種のエスケープシーケンス処理を実行するという点で、Python の欠陥のようです。一時的であっても、エスケープ シーケンス処理を完全にオフにする機能はないようです。最悪。サブクラス化を研究して、Python が文字列で処理したエスケープ シーケンスをインテリジェントに判断し、それらを元の形式に変換するstrようなものを作成する必要があると思います。rawstrこれじゃ面白くない…


Edit2:以下のサンプル正規表現を考えると、別の例:

"^.{0}\xcb\x00\x71[\x00-\xff]"


これを var に割り当てるか、生の指定子を使用せず\x71に関数に渡すと、 は文字に変換されqます。.encode('string-escape')またはを追加しても.replace('\\', '\\\\')、エスケープ シーケンスは処理されます。したがって、次の出力が得られます。

"^.{0}\xcb\x00q[\x00-\xff]"


生の指定子を使用せずに、どうすればこれを停止できますか? エスケープシーケンス処理を「オフ」にするか、「元に戻す」ための方法はありqます\x71か? エスケープ シーケンスの処理が行われる前に、文字列を処理してバックスラッシュをエスケープする方法はありますか?

4

2 に答える 2

2

Python 文字列リテラル (ソース コード表現)、メモリ内の Python 文字列オブジェクト、およびそのオブジェクトを出力する方法 (出力で表現できる形式) の違いについて、理解できる混乱があると思います。

ファイルからバイト文字列にいくつかのバイトを読み取った場合、それらをそのまま書き戻すことができます。

r""ソースコードにのみ存在する 実行時にそのようなことはありません。つまり、同じr"\x""\\x"あり、メモリ内のまったく同じ文字列オブジェクトである可能性さえあります。

入力が壊れていないことを確認するには、各バイトを整数として出力できます。

print " ".join(map(ord, raw_input("input something")))

またはそのままエコーします(違いがある可能性がありますが、"string-escape"問題とは関係ありません):

print raw_input("input something")

識別機能:

def identity(obj):
    return obj

文字列に何もしないと、ユーザーはまったく同じオブジェクトを受け取ります。入力文字列をPythonリテラルとして表現するための簡潔で読みやすい方法と思われる例をドキュメントに提供できます。次のようなバイナリ文字列を扱うのがわかりにくい場合は、"\x20\x01"代わりに ascii hex-representation を受け入れること"2001"ができます (binascii.hexlify/unhexlify を使用して別の文字列に変換できます)。


2 つの言語があるため、正規表現のケースはより複雑です。

  1. エスケープ シーケンスは、文字列リテラルの構文に従って Python によって解釈されます。
  2. 正規表現エンジンは、文字列オブジェクトを独自のエスケープ シーケンスを持つ正規表現パターンとして解釈します
于 2012-12-30T04:58:28.490 に答える
0

参加ルートに行かなければならないと思います。

次に例を示します。

>>> m = {chr(c): '\\x{0}'.format(hex(c)[2:].zfill(2)) for c in xrange(0,256)}
>>>
>>> x = "\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x8a\x2e\x03\x70\x73\x34"
>>> print ''.join(map(m.get, x))
\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x8a\x2e\x03\x70\x73\x34

なぜそれが必要なのか完全にはわかりません。コードが他のコードと相互作用する必要がある場合は、定義された形式に同意し、それに固執することをお勧めします。

于 2012-12-30T01:58:04.673 に答える