9

私はプロジェクト(コンテンツベースの検索)に取り組んでいます。そのために、Ubuntuで「pdftotext」コマンドラインユーティリティを使用して、pdfからいくつかのテキストファイルにすべてのテキストを書き込みます。ただし、箇条書きも書き込みます。ファイルを読み取って各単語にインデックスを付けると、エスケープシーケンスのインデックスも取得されます('\ x01'など)。箇条書き(•)があるためです。

テキストだけが欲しいので、このエスケープシーケンスを削除する方法はありますか?私はこのようなことをしました

escape_char = re.compile('\+x[0123456789abcdef]*')
re.sub(escape_char, " ", string)

しかし、これはエスケープシーケンスを削除しません

前もって感謝します。

4

3 に答える 3

9

問題は\xXX、文字自体ではなく、制御文字の単なる表現であるということです。したがって、文字列\xのを操作しない限り、文字通り一致させることはできません。repr

文字クラスを使用して、印刷できない文字を削除できます。

re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\xff]', '', text)

例:

>>> re.sub(r'[\x00-\x1f\x7f-\xff]', '', ''.join(map(chr, range(256))))
' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
于 2013-02-18T22:20:23.970 に答える
4

あなたの唯一の本当の問題は、バックスラッシュがトリッキーであるということです。文字列では、円記号は特別に扱われる場合があります。たとえば\t、タブに変わります。文字列は特別ではないので\+、文字列は実際にはあなたが期待したものでした。したがって、正規表現コンパイラはそれを調べ\+、正規表現では単なる+文字になります。通常、+は特別な意味(「前のパターンの1つ以上のインスタンス」)を持ち、バックスラッシュはそれをエスケープします。

解決策は、バックスラッシュを2倍にすることです。これにより、1つのバックスラッシュに一致するパターンが作成されます。

パターンをに入れてr''、Pythonがバックスラッシュだけを残す「生の文字列」にします。そうしないと、Pythonの文字列パーサーが2つの円記号を1つの円記号に変換します。\tタブに変わるのと同じよう\\に、単一の円記号に変わります。したがって、生の文字列を使用して、正規表現コンパイラに表示させたいものを正確に配置します。

また、より適切なパターンは、バックスラッシュ、x、16進文字に一致する文字クラスの1つ以上のインスタンスです。これにパターンを書き直しました。

import re

s = r'+\x01+'
escape_char = re.compile(r'\\x[0123456789abcdef]+')
s = re.sub(escape_char, " ", s)

生の文字列を使用する代わりに、通常の文字列を使用して、円記号に十分注意することができます。この場合、4つの円記号を付ける必要があります。文字列パーサーは、二重化された各バックスラッシュを1つのバックスラッシュに変換し、正規表現コンパイラーに2つのバックスラッシュを認識させます。生の文字列を使用する方が簡単です。

また、元のパターンでは、0個以上の16進数が削除されます。私のパターンは1つ以上を削除します。しかし、16進数は常に正確に2桁になる可能性が高いと思います。あるいは、Unicodeでは4桁になる可能性があります。いくつあるかを把握し、これを確実にするパターンを設定する必要があります。2、3、または4桁の16進数に一致するパターンは次のとおりです。

escape_char = re.compile(r'\\x[0123456789abcdef]{2,4}')

そして、これは正確に2つまたは正確に4つに一致するものです。2つの選択肢を作成するには、垂直バーを使用する必要があり、括弧付きのグループを作成する必要があります。ここでは、 (文字通りの単語ではなく、パターンを意味する)の(?:pattern)代わりに、一致しないグループを使用しています。(pattern)patternpattern

escape_char = re.compile(r'\\x(?:[0123456789abcdef]{2,2}|[0123456789abcdef]{4,4})')

これがサンプルコードです。弾丸シーケンスの直後に文字が続き1、このパターンはそれをそのままにします。

import re

s = r'+\x011+'
pat = re.compile(r'\\x(?:[0123456789abcdef]{2,2}|[0123456789abcdef]{4,4})')
s = pat.sub("@", s)
print("Result: '%s'" % s)

これは印刷します:Result: '+@1+'

注:これはすべて、バックスラッシュ文字とそれに続く16進文字を実際に一致させようとしていることを前提としています。「印刷可能な」文字である場合とそうでない場合がある文字バイト値を実際に一致させようとしている場合は、これの代わりに@nneonneoによる回答を使用してください。

于 2013-02-18T22:06:42.393 に答える
1

8ビットのchar値を使用している場合は、事前にいくつかの単純なテーブルを作成し、それらをstr.translate()メソッドと組み合わせて使用​​して、文字列内の不要な文字を非常にすばやく簡単に削除することで、正規表現を使用しないようにすることができます。

import random
import string

allords = [i for i in xrange(256)]
allchars = ''.join(chr(i) for i in allords)
printableords = [ord(ch) for ch in string.printable]
deletechars = ''.join(chr(i) for i in xrange(256) if i not in printableords)

test = ''.join(chr(random.choice(allords)) for _ in xrange(10, 40)) # random string
print test.translate(allchars, deletechars)
于 2013-02-18T23:14:12.600 に答える