home changes contents help options

053:文字をエスケープする/エスケープを外す

エスケープする/エスケープを外す

Ruby レシピブックを参考に作成した、ある文字郡をある文字でエスケープする関数、元に戻す関数です。デフォルトでは Ruby, Python などのリテラル文字列のように「'」「"」「\」の 3 文字を「\」でエスケープします。エスケープ対象は quoted 引数で指定できます。エスケープに使用する文字は escape 引数で指定できます。

import re

def escape(s, quoted=u'\'"\\', escape=u'\\'):
    return re.sub(
            u'[%s]' % re.escape(quoted),
            lambda mo: escape + mo.group(),
            s)

def unescape(s, quoted=u'\'"\\', escape=u'\\'):
    return re.sub(
            ur'%s([%s])' % (re.escape(escape), re.escape(quoted)),
            ur'\1',
            s)

使用してみます。

>>> s = u"abc'def\"ghi"
>>> q = escape(s)
>>> ss = unescape(q)
>>> print s
abc'def"ghi
>>> print q
abc\'def\"ghi
>>> print ss
abc'def"ghi

これらの関数は呼び出すたびに正規表現をコンパイルするので、実行速度は遅めです。処理内容が決まっていて、かつ酷使するとわかっている場合、次のように正規表現オブジェクトを事前にコンパイルしておくとよいでしょう。以下の関数は「'」「"」「\」の 3 文字を「\」でエスケープする関数、元に戻す関数です。

import re

_quote_by_backslash = re.compile(u'([\'"\\\\])')
def quote_by_backslash(s):
    return _quote_by_backslash.sub(ur'\\\1', s)

_remove_backslash = re.compile(ur'\\(.)')
def remove_backslash(s):
    return _remove_backslash.sub(ur'\1', s)

文字を二重にしてエスケープする/エスケープを外す

エスケープ対象を二重にしてエスケープする関数、元に戻す関数です。デフォルトでは「'」「"」の 2 文字をエスケープ対象とします。エスケープ対象は quoted 引数で指定できます。

import re

def escape2(s, quoted=u'\'"'):
    return re.sub(u'([%s])' % re.escape(quoted), ur'\1\1', s)

def unescape2(s, quoted=u'\'"'):
    return re.sub(u'([%s])\\1' % re.escape(quoted) , ur'\1', s)

これも正規表現を事前に決めうちでコンパイルしておけば、実行速度を上げることができます。

import re

_double_quote = re.compile(u'([\'"])')
def double_quote(s):
    return _double_quote.sub(ur'\1\1', s)

_remove_double_quote = re.compile(u'([\'"])\\1')
def remove_double_quote(s):
    return _remove_double_quote.sub(ur'\1', s)

不可視文字を表示する

不可視文字(例えば \n や \r)を \ によるエスケープシーケンスで表示したい場合、 repr 関数が使えます。

>>> a = 'a b\tc\r\n'
>>> print a
a b     c
>>> print repr(a)
'a b\tc\r\n'
>>> print eval(repr(a))
a b     c

特定のエスケープ方式にする

各モジュールには、エスケープ用の関数などが用意されている場合があります。

Python 文字列リテラル

Python には unicode_escape, string_escape というコーデックが存在します。それぞれ、ユニコード文字列、文字列(str 型で表現されたバイナリデータでももちろん可)を Python ソースコードに直接書くための形式、リテラルとしてふさわしい形に変換することができます。逆変換もできます。

>>> s = u'あいうえお'
>>> r = s.encode('unicode_escape')
>>> print r
\u3042\u3044\u3046\u3048\u304a
>>> d = r.decode('unicode_escape')
>>> print d
あいうえお

正規表現

re モジュールには escape 関数があります。正規表現のメタ文字を持つかもしれない文字列を扱うのに役立ちます。

>>> import re
>>> print re.escape(r'\.^$*+?{}|():#')
\\\.\^\$\*\+\?\{\}\|\(\)\:\#
>>>
>>> re.search(r'a\a', r'a\abcde')            # マッチしない、\ は正規表現のメタ文字、重ねる必要がある
>>> re.search(r'a\\a', r'a\abcde')           # これならマッチする
<_sre.SRE_Match object at 0x00A53FA8>
>>> re.search(re.escape(r'a\a'), r'a\abcde') # re.escape 関数で実行時にエスケープ
<_sre.SRE_Match object at 0x00A53F38>

エスケープする/エスケープを外す で提示した escape, unescape 関数でも使用しています。

HTML, XML

HTML, XML における「&」「<」「>」を「&amp;」「&lt;」「&gt;」に変換する関数として xml.sax.saxutils モジュールの escape, quoteattr 関数があります。また、元に戻す関数として unescape 関数があります。詳しくはライブラリリファレンスを参照してください。

電子メール関連

rfc822, base64, binhex,quopri, uu などのモジュールが用意されています。詳しくはライブラリリファレンスを参照してください。