🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
正規表現

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

Python

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

Q&A

解決済

4回答

892閲覧

特定のキーワードに囲まれた文字列を正規表現で抜き出したいが、そのキーワードが別の箇所にも登場する

shinjukuzame

総合スコア12

正規表現

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

Python

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

0グッド

0クリップ

投稿2020/11/24 07:33

編集2020/11/24 23:14

まず、わかりにくい表題ですみません。

環境はpython3系です。

以下例における【影響地域】~【対象機器】間のキーワードを正規表現で抜き出したいです。

python

1import re 2 3message1 = ''' 4【故障発生日時】 2020年06月18日(木)02時14分 5【故障復旧日時】 2020年06月18日(木)02時32分 6【対象サービス】 サービスA 7【影響地域】   山口県 周辺 8【対象機器】   hoge端末 9【状況】     影響地域内にて停止しておりました 10【備考】     特になし''' 11 12match_aff = re.findall(r'【影響地域】((.|\s)*?)【対象機器】', message1) 13 14affect_msg = match_aff [0][0] 15print(affect_msg) 16

これは正常に動作し、「山口県 周辺」が返ります。

しかし、以下の場合正規表現が終わりません。

python

1import re 2 3message2 = ''' 4【故障発生日時】 2020年06月18日(木)02時14分 5【故障復旧日時】 2020年06月18日(木)02時32分 6【対象サービス】 サービスA 7【影響地域】   山口県 周辺 8【対象機器】   hoge端末 9【状況】     影響地域内にて停止しておりました 10【備考】     詳細確認の結果、本故障における影響範囲に変更がございます。 11 ・訂正前 12 【影響地域】   鳥取県 周辺 13 ・訂正後 14 【影響地域】   山口県  周辺''' 15 16 17match_aff = re.findall(r'【影響地域】((.|\s)*?)【対象機器】', message2) 18 19affect_msg = match_aff [0][0] 20print(affect_msg) 21

キーワードの片方である【影響地域】が複数登場したためだと思うのですが、、、

上記message2のようなケースでも、「山口県 周辺」を返せるようにするにはどうしたらよろしいでしょうか?

#【影響地域】の前にスペースやタブが存在しても動作するようにしたいです。

有識者の方、お知恵をいただけますと幸甚です。

https://qiita.com/anqooqie/items/191ad215e93237c77811
等 調べてみたのですが、自力では解決できなかったもので・・・

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

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

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

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

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

toast-uz

2020/11/24 13:12 編集

メッセージは行末改行がエスケープされているため改行なしの文字列になっていますが、正しいですか? 複数行文字列でしたらエスケープは使わずに'''で囲むことで記述可能です。 また、抽出された文字列の前後の空白が残ってしまっていますが、それは意図通りの操作ですか?空白を消す正規表現の方が望ましくはないですか?
shinjukuzame

2020/11/24 23:18

>メッセージは行末改行がエスケープされているため改行なしの文字列になっていますが、正しいですか? ご指摘の通り、意図する状況ではないため修正させていただきました。 前後の空白を除去することはマストではございませんが、より望ましい状況ではあります
guest

回答4

0

正規表現を使わなければよいのではありませんか?

Python

1message2 = "\ 2【故障発生日時】 20200618日(木)0214分\ 3【故障復旧日時】 20200618日(木)0232分\ 4【対象サービス】 サービスA\ 5【影響地域】   山口県 周辺\ 6【対象機器】   hoge端末\ 7【状況】     影響地域内にて停止しておりました\ 8【備考】     詳細確認の結果、本故障における影響範囲に変更がございます。\ 9 ・訂正前\ 10 【影響地域】   鳥取県 周辺\ 11 ・訂正後\ 12 【影響地域】   山口県  周辺" 13 14m2 = message2.split('【') 15msg = '' 16for s in m2: 17 if msg and s.startswith('対象機器】'): 18 affect_msg = msg 19 msg = s[5:] if s.startswith('影響地域】') else '' 20 21print(affect_msg)

投稿2020/11/24 08:58

kazuma-s

総合スコア8224

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

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

shinjukuzame

2020/11/25 00:13

ご回答ありがとうございました。 正規表現に拘らないアプロ―チ、参考になりました。
guest

0

(.|\s)(\S|\s)に変える(空白以外または空白)。

イディオム的には[\S\s]をよく見かけます。

投稿2020/11/24 10:30

otn

総合スコア85893

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

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

shinjukuzame

2020/11/24 23:30

ご回答ありがとうございます。 確かに (\S|\s) と書くと私の意図する通り動作いたしました。 なぜ(\S|\s) と書けば今回のようなケースを回避できるのでしょうか? ひんととなるようなURLや検索のキーワードなど頂けますとありがたいです
guest

0

~~理屈は不明だけど、~~こちらではこれで動いた

python

1match_aff = re.findall(r'【影響地域】((.|\n)*?)【対象機器】', message2)

(a|a)というパターンがReDoSとなるそうなので、
(.|\s)
?というパターンもスペースに対してReDoSになっていたのではないでしょうか。

投稿2020/11/24 09:41

編集2020/11/24 09:57
actorbug

総合スコア2429

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

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

shinjukuzame

2020/11/25 00:12

ご回答ありがとうございます。 #恥ずかしながらReDoSという用語自体知りませんでした。 有益な情報を、ありがとうございました
guest

0

ベストアンサー

質問者様に修正いただいた情報で、回答します。affect_msgのところも変えていますのでご注意ください。

以下の観点で使いやすいと思います。

  • 次の行の【対象機器】に依存していないため、表示順が変わっても対応可能である
  • 得られた結果の前後の空白も削除している
  • match_aff[1]、match_aff[2]などとすることで、備考側も取得するこができる

Python

1match_aff = re.findall(r'【影響地域】\s+(\S.*\S)\s*', message2) 2 3affect_msg = match_aff [0] 4print(affect_msg)

投稿2020/11/24 23:39

toast-uz

総合スコア3266

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

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

shinjukuzame

2020/11/25 00:11

ご親切にありがとうございました。 大変参考になりました。使いやすさ まで考慮いただき、感謝申し上げます。
otn

2020/11/25 03:52

【影響地域】は必ず1行という前提があったのですか? 質問文のコードが次のタグを見てるので、てっきり複数行前提かと思っていたのですが。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問