前提・実現したいこと
文字列からキーワードを抽出するために、正規表現でのマッチを試みています。が、期待した結果を得られません。正規表現での式が下手なところに原因があるはずですが、どのように式を組み立てれば良いか教えてください。
python
1a = "cat:AA|a" 2b = "cat:AA;BBB|b" 3c = "cat:AA;BBB;CCCC|c"
キーワードはカテゴリ名のあと:
の後から始まり;
で区切られ|
で終わります。
上記の文字列、a, b, c があったとして、cat:のあと、AAなどのキーワード自体が可変長で、なおかつ、キーワードの個数も可変長です(上の場合aはキーワード1個、bはキーワード2個などのように)
発生している問題・エラーメッセージ
python
1import re 2a = "cat:AA|a" 3b = "cat:AA;BBB|b" 4c = "cat:AA;BBB;CCCC|c" 5regex = re.compile("^([^:]+):([^;|]+);?([^;|]+)?") 6re.findall(regex, a);re.findall(regex, b);re.findall(regex, c) 7 8>>> 9[('cat', 'AA', '')] # <- 最後尾の長さゼロの文字列''が不要 10[('cat', 'AA', 'BBB')] 11[('cat', 'AA', 'BBB')] # <- 'CCCC'が取得できてない
期待している結果
python
1('cat', 'AA') 2('cat', 'AA', 'BBB') 3('cat', 'AA', 'BBB', 'CCCC')
補足情報(FW/ツールのバージョンなど)
python 3.7
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
二段階に分けて考えると楽です。
- まず : と | の間を抽出して、
- 次に ; で分割
Python
1for src in [a, b, c]: 2 ret = re.search(r'([a-z]+):([A-Z;]+)\|', src) 3 if not ret: 4 continue 5 6 ret = [ret.group(1), *ret.group(2).split(';')] 7 print(ret)
仕様に依っては次のように書いても良いでしょう。
Python
1for src in [a, b, c]: 2 ret = re.findall(r'[:;]?([a-zA-Z]+)(?=[:;|])', src) 3 print(ret)
あるいは、これくらい単純化できるかもしれません。
Python
1for src in [a, b, c]: 2 ret = re.split(r'[:;|]', src)[:-1] 3 print(ret)
投稿2019/10/04 01:51
編集2019/10/04 01:59総合スコア35660
0
最初は、つぎのようにするとよいです。
- 入力文字列をその意味を解釈して内部的なデーア後続に変換
- その青での処理ようにデータ後続を変換する。
zz.py
pythpn3
1import re 2 3def parse(line): 4 m = re.search(r"^(.*)\:(.*)\|(.*)?", line) 5 return { 6 "cat": m.group(1), 7 "tags": sorted(set(m.group(2).split(";"))), 8 "name": m.group(3) 9 } 10 11a = "cat:AA|a" 12b = "cat:AA;BBB|b" 13c = "cat:AA;BBB;CCCC|c" 14d = "cat:Z;CCCC;BBB;A;BBB;CCCC|d" 15 16# dict に変換する 17ary = map(parse, (a, b, c, d)) 18 19# 表示用に整形する 20ary2 = map(lambda x: [x["cat"]] + [t for t in x["tags"]], ary) 21print(list(ary2)) 22
ここでは キーワードの意味をすこしだけ考慮して、重複を除去する / ソートする といったことも行っています。
開映と変に分けて行うのは処理が冗長になりがちです。
この質問の場合なら、直接 表示用のデーアにしてしまうようなことも考えてのよいかもしれません。
(ただし、将来的に 入寮データの変化、処理用データ後続の変化があったときに対応しにくくなります)
zz0.py
python3
1import re 2 3a = "cat:AA|a" 4b = "cat:AA;BBB|b" 5c = "cat:AA;BBB;CCCC|c" 6 7ary = map(lambda x: re.sub(":|;", "|", x).split("|")[:-1], [a, b, c])
区切り文字をすべて "|" にしてしまってから、 split して 最後の単語を取り除くということで実現させてしまっています。
なお、この回答例では入力データのエラーチェックをしていません。
エラーチェックをしだすと、コードはもっと複雑になっていきます。
投稿2019/10/04 22:17
総合スコア22324
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
こんにちは
キャプチャしないグループ (?:
・・・)
を使って、以下でどうでしょう?
Python3
1regex = re.compile("(?:^[^:]+)|(?:[^:;|]+)|(?:[^;|]+$)")
以下は、Repl.it に作成した動作確認用のコードです。
- 動作確認用 Repl.it: https://repl.it/@jun68ykt/Q215284
画面上部中央のrunボタンをクリックすると実行され、以下のように、結果が右側のコンソールに出力されます。
追記
質問者さまから頂きましたコメントにより見直しまして、より短い正規表現の以下でも、意図通りのリストが得られます。
python
1regex = re.compile("[^:;|]+")
- 動作確認用 Repl.it: https://repl.it/@jun68ykt/Q215284-2
投稿2019/10/04 03:54
編集2019/10/04 07:02総合スコア9058
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/10/04 06:59
2019/10/04 07:50
2019/10/04 10:30
2019/10/04 10:59
2019/10/04 11:12
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。