1

以下のパターンを使用して文字列をトークン化しようとしています。

>>> splitter = re.compile(r'((\w*)(\d*)\-\s?(\w*)(\d*)|(?x)\$?\d+(\.\d+)?(\,\d+)?|([A-Z]\.)+|(Mr)\.|(Sen)\.|(Miss)\.|.$|\w+|[^\w\s])')
>>> splitter.split("Hello! Hi, I am debating this predicament called life. Can you help me?")

次の出力が得られます。誰かが私が修正する必要があることを指摘してもらえますか?私は「なし」の束全体について混乱しています。また、文字列をトークン化するためのより良い方法がある場合は、追加のヘルプを本当にいただければ幸いです。

['', 'Hello', None, None, None, None, None, None, None, None, None, None, '', '!', None, None, None, None, None, None, None, None, None, None, ' ', 'Hi', None,None, None, None, None, None, None, None, None, None, '', ',', None, None, None, None, None, None, None, None, None, None, ' ', 'I', None, None, None, None, None, None, None, None, None, None, ' ', 'am', None, None, None, None, None, None,None, None, None, None, ' ', 'debating', None, None, None, None, None, None, None, None, None, None, ' ', 'this', None, None, None, None, None, None, None, None, None, None, ' ', 'predicament', None, None, None, None, None, None, None, None, None, None, ' ', 'called', None, None, None, None, None, None, None, None, None, None, ' ', 'life', None, None, None, None, None, None, None, None, None, None, '', '.', None, None, None, None, None, None, None, None, None, None, ' ', 'Can', None, None, None, None, None, None, None, None, None, None, ' ', 'you', None, None, None, None, None, None, None, None, None, None, ' ', 'help', None, None,None, None, None, None, None, None, None, None, ' ', 'me', None, None, None, None, None, None, None, None, None, None, '', '?', None, None, None, None, None, None, None, None, None, None, '']

私が欲しい出力は次のとおりです:-

['Hello', '!', 'Hi', ',', 'I', 'am', 'debating', 'this', 'predicament', 'called', 'life', '.', 'Can', 'you', 'help', 'me', '?']

ありがとうございました。

4

5 に答える 5

4

re.splitトークナイザーとして使用すると、すぐにパフがなくなります。望ましいのはfindall(またはmatchループ内で)代替パターンを使用することですthis|that|another|more

>>> s = "Hello! Hi, I am debating this predicament called life. Can you help me?"
>>> import re
>>> re.findall(r"\w+|\S", s)
['Hello', '!', 'Hi', ',', 'I', 'am', 'debating', 'this', 'predicament', 'called', 'life', '.', 'Can', 'you', 'help', 'me', '?']
>>>

これは、トークンを 1 つ以上の「単語」文字、または空白ではない単一の文字として定義します。(アンダースコアを許可する)の代わりに[A-Za-z]or[A-Za-z0-9]または何か他のものを好むかもしれません。\w次のようなものが必要になる場合もありますr"[A-Za-z]+|[0-9]+|\S"

Sen.Mr.および(およびMissに何が起こったのか ?)のようなものが重要な場合、正規表現はそれらをリストするべきではなく、 で終わるトークンを定義するだけであり、辞書または可能性のある略語のセットを用意する必要があります。MrsMs.

テキストを文に分割するのは複雑です。nltk車輪の再発明を試みるのではなく、パッケージを見たいと思うかもしれません。

更新:トークンのタイプを区別する必要がある場合、または区別したい場合は、if/elif/elif/.../else の (おそらく長い) チェーンなしで、次のようなインデックスまたは名前を取得できます。

>>> s = "Hello! Hi, I we 0 1 987?"

>>> pattern = r"([A-Za-z]+)|([0-9]+)|(\S)"
>>> list((m.lastindex, m.group()) for m in re.finditer(pattern, s))
[(1, 'Hello'), (3, '!'), (1, 'Hi'), (3, ','), (1, 'I'), (1, 'we'), (2, '0'), (2,     '1'), (2, '987'), (3, '?')]

>>> pattern = r"(?P<word>[A-Za-z]+)|(?P<number>[0-9]+)|(?P<other>\S)"
>>> list((m.lastgroup, m.group()) for m in re.finditer(pattern, s))
[('word', 'Hello'), ('other', '!'), ('word', 'Hi'), ('other', ','), ('word', 'I'), ('word', 'we'), ('number', '0'), ('number', '1'), ('number', '987'), ('other'
, '?')]
>>>
于 2010-08-03T01:48:01.603 に答える
4

NLTKのトークナイザーをお勧めします。次に、面倒な正規表現について自分で心配する必要はありません。

>>> import nltk
>>> nltk.word_tokenize("Hello! Hi, I am debating this predicament called life. Can you help me?")
['Hello', '!', 'Hi', ',', 'I', 'am', 'debating', 'this', 'predicament', 'called', 'life.', 'Can', 'you', 'help', 'me', '?']
于 2010-08-03T02:12:04.693 に答える
2

何かが欠けている可能性がありますが、次のようなものがうまくいくと思います:

s = "Hello! Hi, I am debating this predicament called life. Can you help me?"
s.split(" ")

これは、スペースが必要であると仮定しています。次の行に沿って何かを取得する必要があります。

['Hello!', 'Hi,', 'I', 'am', 'debating', 'this', 'predicament', 'called', 'life.', 'Can', 'you', 'help', 'me?']

これにより、特定のピースが必要な場合、おそらくそれをループして必要なものを取得できます。

うまくいけば、これは役に立ちます....

于 2010-08-03T01:19:37.043 に答える
1

これらすべての 's を取得する理由Noneは、正規表現に 's で区切られた括弧で囲まれたグループが多数あるためです|。正規表現が一致を見つけるたびに、 で指定された選択肢の 1 つだけに一致し|ます。他の未使用の選択肢の括弧で囲まれたグループは に設定されNoneます。またre.split、定義により、一致するたびに括弧で囲まれたすべてのグループの値が報告されるためNone、結果には多くの 's が含まれます。

それらを非常に簡単に除外できますが(たとえばtokens = [t for t in tokens if t]、または同様のもの)、splitトークン化に必要なツールではないと思います。split空白を単に捨てるためのものです。何かをトークン化するために正規表現を使用したい場合は、別の方法のおもちゃの例を次に示します (使用しているモンスターを展開するつもりはありません... re.VERBOSENed の愛のためにオプションを使用してください。 ..しかし、うまくいけば、このおもちゃの例があなたにアイデアを与えるでしょう):

tokenpattern = re.compile(r"""
(?P<words>\w+) # Things with just letters and underscores
|(?P<numbers>\d+) # Things with just digits
|(?P<other>.+?) # Anything else
""", re.VERBOSE)

(?P<something>...ビジネスでは、以下のコードで、探しているトークンのタイプを名前で識別できます。

for match in tokenpattern.finditer("99 bottles of beer"):
  if match.group('words'):
    # This token is a word
    word = match.group('words')
    #...
  elif match.group('numbers'):
    number = int(match.group('numbers')):
  else:
    other = match.group('other'):

これはまだ|'s で区切られた括弧で囲まれたグループの束を使用しているため、コードと同じことが起こることに注意してください: 一致ごとに、1 つのグループが定義され、他のグループは に設定されNoneます。このメソッドはそれを明示的にチェックします。

于 2010-08-03T01:49:35.063 に答える
0

おそらく彼はそれを意図していたわけではありませんが、John Machin のコメント「str.split は開始する場所ではありません」( Frank V の回答後の交換の一部として) は、ちょっとした挑戦でした。そう ...

the_string = "Hello! Hi, I am debating this predicament called life. Can you help me?"
tokens = the_string.split()
punctuation = ['!', ',', '.', '?']
output_list = []
for token in tokens:
    if token[-1] in punctuation:
        output_list.append(token[:-1])
        output_list.append(token[-1])
    else:
        output_list.append(token)
print output_list

これは、要求された出力を提供するようです。

確かに、ジョンの答えは、コードの行数に関してはより単純です。ただし、この種のソリューションをサポートするためのポイントがいくつかあります。

ジェイミー・ザウィンスキーの「問題に直面したときに、正規表現を使用することはわかっている」と考える人もいますが、これにはまったく同意できません。今、彼らには 2 つの問題があります。(私が読んだ限りでは、彼もそうではありませんでした。) これを引用する私のポイントは、正規表現に慣れていないと、正規表現を機能させるのが面倒になる可能性があるということです。

また、通常は問題になりませんが、 timeitで測定すると、上記のソリューションのパフォーマンスは一貫して正規表現のソリューションよりも優れていました。上記のソリューション (print ステートメントを削除したもの) は、約 8.9 秒かかりました。John の正規表現ソリューションは、約 11.8 秒で到着しました。これには、2.4 GHz で動作するクアッド コア デュアル プロセッサ システムで 100 万回の反復ごとに 10 回の試行が含まれていました。

于 2010-08-04T02:06:22.533 に答える