0

次のような文字列からサブ文字列をキャプチャしようとしています

'some string, another string, '

結果一致グループを

('some string', 'another string')

私の現在の解決策

>>> from re import match
>>> match(2 * '(.*?), ', 'some string, another string, ').groups()
('some string', 'another string')

動作しますが、実用的ではありません。もちろん、ここで示していることは、実際のプロジェクトで行っていることと比較して、複雑さの点で大幅に削減されています。1つの「ストレート」(計算されていない)正規表現パターンのみを使用したいと思います。残念ながら、私の試みはこれまで失敗しました:

{2}は文字列全体ではなくスペースにのみ適用されるため、これは一致しません(結果としてなし)。

>>> match('.*?, {2}', 'some string, another string, ')

繰り返される文字列の前後に括弧を追加すると、結果にコンマとスペースが含まれます

>>> match('(.*?, ){2}', 'some string, another string, ').groups()
('another string, ',)

別の一連の括弧を追加することでそれは修正されますが、私はあまりにも多くなります。

>>> match('((.*?), ){2}', 'some string, another string, ').groups()
('another string, ', 'another string')

非キャプチャ修飾子を追加すると、結果は改善されますが、それでも最初の文字列が失われます

>>> match('(?:(.*?), ){2}', 'some string, another string, ').groups()
('another string',)

近くにいるような気がしますが、正しい道を見つけることができないようです。

誰かが私を助けることができますか?私が見ていない他のアプローチはありますか?


最初のいくつかの応答の後に更新します。

まず、みなさん、ありがとうございました。よろしくお願いします!:-)

元の投稿で述べたように、実際のコアの問題を描写するために、質問の多くの複雑さを省略しました。手始めに、私が取り組んでいるプロジェクトでは、大量のファイル(現在は1日あたり数万)をさまざまな行ベースの形式で解析しています(現在は5つ、まもなく25まで、場合によっては数百)。XML、JSON、バイナリ、その他のデータファイル形式もありますが、引き続き焦点を当てましょう。

多数のファイル形式に対処し、それらの多くが行ベースであるという事実を利用するために、ファイルを次々にロードし、すべての行に正規表現を適用して大きなファイルを返す、やや一般的なPythonモジュールを作成しました。一致するデータ構造。このモジュールはプロトタイプです。製品版では、パフォーマンス上の理由からC ++バージョンが必要です。これは、Boost :: Pythonを介して接続され、複雑さのリストに正規表現の方言の主題を追加する可能性があります。

また、2回の繰り返しはありませんが、現在のゼロから70(またはそれくらい)の間で変化する量です。コンマは必ずしもコンマではなく、最初に言ったことにもかかわらず、正規表現パターンの一部は実行時に計算する必要があります。「動的」な量を減らし、可能な限り多くの「固定」パターンを使用する理由があるとしましょう。

つまり、一言で言えば、正規表現を使用する必要があります。


言い換えると、問題の核心は次のようになります。たとえば、中括弧の繰り返しを含み、キャプチャできるPython正規表現表記はありますか。

'some string, another string, '

の中へ

('some string', 'another string')

うーん、それはおそらくそれをあまりにも絞り込みすぎます-しかし、あなたがそれを行う方法は間違っています:-D


2回目の言い換え:結果に最初の文字列(「いくつかの文字列」)が表示されないのはなぜですか?正規表現が一致を生成するのに(何かが2つある必要があることを示す)、1つの文字列(2番目の文字列)しか返さないのはなぜですか?

数値以外の繰り返しを使用した場合、つまり{2}の代わりに+を使用した場合でも、問題は同じです。

>>> match('(?:(.*?), )+', 'some string, another string, ').groups()
('another string',)

また、返されるのは2番目の文字列ではなく、最後の文字列です。

>>> match('(?:(.*?), )+', 'some string, another string, third string, ').groups()
('third string',)

繰り返しになりますが、あなたの助けに感謝します。私が実際に知りたいことを見つけようとしている間、ピアレビューがどれほど役立つか私を驚かせることをやめません...

4

6 に答える 6

5

この問題についてあなたが説明した以上のものがない限り、正規表現を使用する意味はわかりません。これは、基本的な文字列メソッドを使用して処理するのは非常に簡単です。

[s.strip() for s in mys.split(',') if s.strip()]

または、タプルである必要がある場合:

tuple(s.strip() for s in mys.split(',') if s.strip())

コードも読みやすくなっています。これが当てはまらない場合は教えてください。


編集:わかりました、確かに、この問題には当初考えられていた以上のものがあります。ただし、これは歴史的な目的のために残しておきます。(私は「規律」ではないと思います:))

于 2011-03-01T21:38:25.780 に答える
4

説明したように、この正規表現は正常に機能すると思います。

import re
thepattern = re.compile("(.+?)(?:,|$)") # lazy non-empty match 
thepattern.findall("a, b, asdf, d")     # until comma or end of line
# Result:
Out[19]: ['a', ' b', ' asdf', ' d']

ここで重要なのは、findallではなくを使用することですmatch。あなたの質問の言い回しはあなたが好むことを示唆していますが、それはここでの仕事に適したツールではありません-それは正規表現のmatch対応するグループごとに正確に1つの文字列を返すように設計されています。( )'文字列の数'は可変であるため、正しいアプローチはまたはのいずれfindallかを使用することsplitです。

これが必要なものでない場合は、質問をより具体的にしてください。

編集:リストではなくタプルを使用する必要がある場合:

tuple(Out[19])
# Result
Out[20]: ('a', ' b', ' asdf', ' d')
于 2011-03-01T22:49:27.800 に答える
2
import re

regex = " *((?:[^, ]| +[^, ])+) *, *((?:[^, ]| +[^, ])+) *, *"

print re.match(regex, 'some string, another string, ').groups()
# ('some string', 'another string')
print re.match(regex, ' some string, another string, ').groups()
# ('some string', 'another string')
print re.match(regex, ' some string , another string, ').groups()
# ('some string', 'another string')
于 2011-03-01T21:27:45.873 に答える
1

不快感はありませんが、正規表現について学ぶことは明らかにたくさんあります。最終的には、正規表現はこの仕事を処理できないということを学びます。この特定のタスクは正規表現で実行できると確信していますが、それではどうしますか?解析するファイル形式が何百もある可能性があるとあなたは言います!正規表現と基本的に互換性のないJSONとXMLについても言及されました。

自分に有利に働きましょう。正規表現を忘れて、代わりにpyparsingを学びましょう。または、Pythonを完全にスキップして、ANTLRのようなスタンドアロンのパーサジェネレータを使用します。どちらの場合でも、ほとんどのファイル形式の文法はすでに作成されていることに気付くでしょう。

于 2011-03-02T01:16:56.743 に答える
0

問題の核心は次のように要約すると思います。たとえば、中括弧の繰り返しを含み、「ある文字列、別の文字列」をキャプチャできるPython正規表現表記はありますか?

そのような表記はないと思います。

ただし、正規表現はNOTATIONだけの問題ではありません。つまり、正規表現を定義するために使用されるRE文字列です。それはツール、つまり機能の問題でもあります。

残念ながら、最初の質問の文字列は問題の一部にすぎず、実際の文字列ははるかに長いため、findallを使用できません。したがって、findallは、複数の正規表現のfindalls/一致/検索を実行した場合にのみ機能します。

遅滞なくより多くの情報を提供する必要があります。制約が何であるかをより迅速に理解できます。私の意見では、問題が明らかになったときに問題に答えるために、findall()は確かにOKです。

import re

for line in ('string one, string two, ',
             'some string, another string, third string, ',
             # the following two lines are only one string
             'Topaz, Turquoise, Moss Agate, Obsidian, '
             'Tigers-Eye, Tourmaline, Lapis Lazuli, '):

    print re.findall('(.+?), *',line)

結果

['string one', 'string two']
['some string', 'another string', 'third string']
['Topaz', 'Turquoise', 'Moss Agate', 'Obsidian', 'Tigers-Eye', 'Tourmaline', 'Lapis Lazuli']

さて、あなたはあなたの質問で「多くの複雑さを省略した」ので、findall()は偶然にもこの複雑さを保持するのに不十分である可能性があります。次に、finditer()が使用されます。これにより、一致するグループの選択がより柔軟になります。

import re

for line in ('string one, string two, ',
             'some string, another string, third string, ',
             # the following two lines are only one string
             'Topaz, Turquoise, Moss Agate, Obsidian, '
             'Tigers-Eye, Tourmaline, Lapis Lazuli, '):

    print [ mat.group(1) for mat in re.finditer('(.+?), *',line) ]

同じ結果が得られ、mat.group(1)の代わりに他の式を記述することで複雑化できます。

于 2011-03-11T09:56:50.990 に答える
-1

これを要約すると、「動的」な方法で正規表現パターンを構築することにより、すでに最良のソリューションを使用しているようです。

>>> from re import match
>>> match(2 * '(.*?), ', 'some string, another string, ').groups()
('some string', 'another string')

the

2 * '(.*?)

私がダイナミックとはどういう意味ですか。別のアプローチ

>>> match('(?:(.*?), ){2}', 'some string, another string, ').groups()
('another string',)

(GlennとAlanが親切に説明したように)という事実のために、望ましい結果を返すことができません

一致すると、キャプチャされたコンテンツは、キャプチャグループが繰り返されるたびに上書きされます

みなさん、ありがとうございました!:-)

于 2011-03-10T12:50:15.303 に答える