2013-05-10 21 views
7

私は区切り文字として-+====+、および空白を使用して文字列を分割したいです。デリミタが空白でない限り、その区切り文字を保持したい。Pythonの正規表現 - 余分なマッチング

私は次のコードでこれを達成しようとした

def tokenize(s): 
    import re 
    pattern = re.compile("(\-|\+\=|\=\=|\=|\+)|\s+") 
    return pattern.split(s) 

print(tokenize("hello-+==== =+ there")) 

私はほとんど何

['hello', '-', '', '+=', '', '==', '', '=', '', None, '', '=', '', '+', '', None, 'there'] 

を得たが、私は出力が

['hello', '-', '+=', '==', '=', '=', '+', 'there'] 

ことが期待私はほんの少しの無関係なNoneと空の文字列があることを除いて、私は望んでいました。

なぜこのように動作していますか、私が望むものを得るためにはどうすれば変更できますか?

+0

空の文字列は、お互いにすぐ隣に2つの一致する文字があるためです。したがって、分割すると、それらの間に '''が付きます。それは混乱のグループをキャプチャすると直感的ではありません – jozefg

答えて

3

re.splitがマッチの間にある文字列のビットの配列を返す:(@Laurenceゴンサルベスが指摘したように、これは、その主な用途である。)

['hello', '', '', '', '', '', '', '', 'there'] 

-の間に空の文字列そして、など+=+===

あなたが(\-|\+\=|\=\=|\=|\+)代わりの(?:\-|\+\=|\=\=|\=|\+)、キャプチャグループの一致が散在しているビットを使用しているので、あなたがキャプチャグループ(すなわち、使用しているので、ドキュメントは、説明したよう:

['hello', '-', '', '+=', '', '==', '', '=', '', None, '', '=', '', '+', '', None, 'there'] 

Noneあなたのパターンの\s+半分が一致した場所に対応します。そのような場合、キャプチャグループは何もキャプチャしませんでした。

re.splitのためのドキュメントを見てから、私は(あなたが好む場合、またはfilter)簡単なリスト内包が、それは試合の間に空の文字列を破棄持っている簡単な方法が表示されていない簡単None Sを破棄することができます空の文字列:

def tokenize(s): 
    import re 
    pattern = re.compile("(\-|\+\=|\=\=|\=|\+)|\s+") 
    return [ x for x in pattern.split(s) if x ] 

一つの最後の音符:あなたがこれまでに説明した内容については、これは正常に動作しますが、あなたのプロジェクトが行く方向に応じて、あなたは適切な解析ライブラリに切り替えたいこと。 The Python wikiには、ここでのオプションの概要がよく分かります。

+0

中間のビットを返すことは、str.splitに似た、「主な振舞い」のようなものであることに注意してください。キャプチャは、特別な機能のようなものです。 –

1

このパターンは何をしたいとのラインでよりです:

\s*(\-|\+\=|\=\=|\=|\+)\s* 

あなたが期待するべきであるとして、あなたはまだ、しかし、各分割の間に空の文字列を取得します。デフォルトで

+0

それは2つのトークンに "こんにちはそこ"を壊すことはありません、私はOPの意図は、区切り文字として空白を使用すると考えています。 – rici

2

なぜこのように動作していますか?

改訂版のドキュメントによると、split:

キャプチャカッコをパターンで使用すると、パターン内のすべてのグループのテキストも結果リストの一部として返されます。

これは文字通り正しくあります。キャプチャ括弧が使用されている場合は、それらが一致しているかどうかに関わらず、すべてのグループのテキストが返されます。どんなものとも一致しなかったものはNoneを返します。

常にsplitと同じように、2つの連続した区切り文字が空の文字列を区切ると見なされるため、空の文字列が散在します。

どのようにして私が欲しいものを得ることができますか?

最も簡単な解決策は、出力をフィルタリングすることである。

filter(None, pattern.split(s)) 
0

はこれを試してみてください:おそらく

def tokenize(s): 
    import re 
    pattern = re.compile("(\-|\+\=|\=\=|\=|\+)|\s+") 
    x = pattern.split(s) 
    result = [] 
    for item in x: 
    if item != '' and item != None: 
     result.append(item) 
    return result 

print(tokenize("hello-+==== =+ there")) 
2

re.findallはあなたのために、より適しているだろうか?

>>> re.findall(r'-|\+=|==|=|\+|[^-+=\s]+', "hello-+==== =+ there") 
['hello', '-', '+=', '==', '=', '=', '+', 'there'] 
+0

私はあなたの解決策に懸念を抱いています。後で、より多くの区切り文字(例えば、 '*'、 '&&')をサポートしたいと思っていて、 '[^ - + = \ s] +パターンはより複雑になります。 – math4tots

+0

デリミタではないトークンに関する規則はありますか?たぶんあなたは、例えば、 '[^ - + = \ s] +'の代わりに '\ w +'を使います。 –

関連する問題