質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

674閲覧

正規表現、マッチが貪欲すぎる……

hacosato

総合スコア48

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2020/02/08 12:49

Pythonで正規表現を書いているんですが上手にマッチさせられません…。
下記のコード、果物と色の組み合わせをマッチさせたいのですが、思ったようにいきません……。

python3

1import re 2menu = ''' 3<item>りんご</item> 4 <price>120</price> 5<item>みかん</item> 6 <price>300</price> 7 <color>オレンジ</color> 8<item>ぶどう</item> 9 <price>400</price> 10 <color>むらさき</color> 11''' 12result = re.finditer(r'<item>(.+?)</item>.+?<color>(.+?)</color>' 13 ,menu 14 ,flags=re.DOTALL) 15for each in result: 16 print(each.groups())

↓こういう答えが返ってきてほしい

('みかん', 'オレンジ') ('ぶどう', 'むらさき')

↓実際に返ってくる答え(りんごはオレンジではない……)

('りんご', 'オレンジ') ('ぶどう', 'むらさき')

こういう風に戻ってくる原理はわかっているつもり(正規表現の中の丸括弧に入っていない .+? がわたしの想定を超えて貪欲なのですよね)ですが、理想通りに変える方法が思い当たりません。
上から順になぞっていって、<color>タグを見つけたときに、さかのぼっていちばん近い<item>を見つけてもらえたらいいのですが……。

なお、上記はわかりやすくXMLみたいなものを書いているのですが、実際にわたしが取り組んでいるデータはこんな感じではない(Wikipediaのダンプデータ)ので、タグの階層関係などに依存しない方法があれば知りたいです。

Python 3.6.5

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

直感的にはこんな感じで、二段階でやります。

Python

1result = re.finditer(r'<item>.*?(?=<item>|$)' 2 ,menu 3 ,flags=re.DOTALL) 4for each in result: 5 result2 = re.finditer(r'<item>(.+?)</item>.+?<color>(.+?)</color>' 6 ,each.group() 7 ,flags=re.DOTALL) 8 for each2 in result2: 9 print(each2.groups())

1つの正規表現で、出来るかもしれないけど、出来たとしても読解困難になることは間違いなさそうです。
#追記
それほど読解困難じゃなくて出来た気がします。質問文のデータでしかテストしてませんが。

Python

1result = re.finditer( 2 r'<item>((?:(?!</item>).)+?)</item>(?:(?!<item>).)+?<color>(.+?)</color>' 3 ,menu 4 ,flags=re.DOTALL) 5for each in result: 6 print(each.groups())

投稿2020/02/08 13:13

編集2020/02/08 13:32
otn

総合スコア85901

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otn

2020/02/08 13:41

私がやるなら、二段階方式ですね。要件が変わったときに修正が楽。
hacosato

2020/02/09 09:37

ありがとうございました。 どちらもきちんと動くの確認できました。 2行のほうは理解もできました。 1行のほうはよくわからなかったのですが、 https://regexper.com/#%3Citem%3E%28%28%3F%3A%28%3F!%3C%5C%2Fitem%3E%29.%29%2B%3F%29%3C%5C%2Fitem%3E%28%3F%3A%28%3F!%3Citem%3E%29.%29%2B%3F%3Ccolor%3E%28.%2B%3F%29%3C%5C%2Fcolor%3E 可視化しながら触ってみたので、仕組みもわかったと思います。 ありがとうございました。
otn

2020/02/09 09:52

この問題もそうですが、1つの正規表現でやろうとするのは、不可能あるいはメンテ困難になる場合があります。 例えば、「★★★を含んで☆☆☆を含まない行を処理する」は、 if re.search("★★★",line) and not re.search("☆☆☆",line): が、明快です。
guest

0

こんにちは

この回答はご質問の本題からは逸れます。何卒ご了承ください。(ご質問の本題に対する回答としては、otnさんが追記のほうで挙げられている正規表現になるかと思います。)

題意の解決のためには、ご質問に挙げられているサンプルのテキストから、

python

1[ 2 ('item', 'りんご'), 3 ('price', '120'), 4 ('item', 'みかん'), 5 ('price', '300'), 6 ('color', 'オレンジ'), 7 ('item', 'ぶどう'), 8 ('price', '400'), 9 ('color', 'むらさき') 10]

というリスト(あるいは同等のiterable)を作るのが分かりやすいと思われました。正規表現は、一組の

<TagName>Value</TagName>

を得るためにのみ使います。以下はこの考えによる、ご質問の回答となるコードです。

python

1import re 2 3menu = ''' 4<item>りんご</item> 5 <price>120</price> 6<item>みかん</item> 7 <price>300</price> 8 <color>オレンジ</color> 9<item>ぶどう</item> 10 <price>400</price> 11 <color>むらさき</color> 12''' 13 14item = None 15 16for name, value in re.findall(r'<([a-z]+)>(.*?)</\1>', menu): 17 if name == 'item': 18 item = value 19 elif name == 'color': 20 print((item, value)) 21

以上、参考になれば幸いです。

投稿2020/02/08 15:58

編集2020/02/08 16:12
jun68ykt

総合スコア9058

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hacosato

2020/02/09 09:38

ありがとうございます。 上から順になぞっていって適切かどうかを判断していく感じ、わたしが思うのと似た感じの構造になっていて理解しやすいです!
jun68ykt

2020/02/09 10:44

どういたしまして。 > わたしが思うのと似た感じの構造になっていて理解しやすいです! ありがとうございます。 実務上では、あまり複雑な正規表現を書くと、後のメンテナンスが大変なので、私のこの回答のようなことをやって、正規表現に任せる仕事はほどほどにしておくという判断はあり得ることではありますが、とはいえ、hacosatoさんのこのご質問の動機となっているであろう、「ひとつの正規表現で何もかも一気に片付けてやろう」という心構えは、正規表現の上達のためにはとても良いと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問