前提・実現したいこと
pythonとpyQtで作られているオープンソースのankiという単語帳アプリに検索して置換するという機能があり、そこでPythonの正規表現を使って単語帳の中身をある条件で置換をしたいのですがうまくいきません。
具体的には以下のように、置換前の「@@@の直後の1以上999以下の数値」を取得して置換後の文字列「<img src="hogehoge_xxx.png" />」のxxxに埋め込みたいです。このxxxは本のページ数です。以後この置換前の文字を便宜上サンプルとします。
#置換前のサンプル
@@@123
@@@23
@@@34
@@@45
@@@56
↓
#置換後のサンプル(この結果が欲しい)
<img src="hogehoge_123.png" />
<img src="hogehoge_23.png" />
<img src="hogehoge_34.png" />
<img src="hogehoge_45.png" />
<img src="hogehoge_56.png" />
このように取得したいのですが、この123や23や34などを抽出したいときどのように書くのでしょうか?re.sub()
で\1
を使用しても意図したようにいきませんでした。(参照:reモジュール)
発生している問題・エラーメッセージ
上記サンプルを以下の画像のようにankiアプリ上で正規表現を使用して置換すると数字の一桁目だけが抽出されてしまいます。
#置換前のサンプル
@@@123
@@@23
@@@34
@@@45
@@@56
#置換後のサンプル(数字の最後の一桁だけ抽出される)
img src="hogehoge_3.png"
img src="hogehoge_3.png"
img src="hogehoge_4.png"
img src="hogehoge_5.png"
img src="hogehoge_6.png"
上記の問題では置換をGUIで実行していますが、ankiのソースコードのl.497のrepl関数を見る限り、pythonではおそらく以下のようなことをしていると考えています。しかし私のpowershell上での実行結果は適切に表示されず、確認できない状態になってしまっています。ただ、適切に表示されない部分(=)が一文字なので置換後のサンプルと多分同じ挙動だと思われます。
#resub.py
import re
regex = re.compile("@@@(\d){1,3}")
reSub = re.sub(regex,"img src=hogehoge_\1.png","@@@123\n@@@23\n@@@34\n@@@45\n@@@56\n")
print(reSub)
PS > python -V
Python 2.7.14
PS > python .\resub.py
img src=hogehoge_.png
img src=hogehoge_.png
img src=hogehoge_.png
img src=hogehoge_.png
img src=hogehoge_.png
該当のソースコード
ankiのソースコードのfindReplace関数(l.481からl.528)で検索して置換するを実装をしていると思われます。
試したこと
①サンプルを置換文字列\2
で実行 → 無効な処理と表示される(おそらくエラー)
②サンプルを置換文字列\0
で実行 → サンプルがすべて消える
#③の結果
333
333
444
555
666
補足情報(言語/FW/ツール等のバージョンなど)
Windows10
Python2系
以上になりますがどうぞよろしくお願いいたします。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+2
数字をマッチさせたいならこうでは?
regex = re.compile("@@@(\d){1,3}")
↓
regex = re.compile("@@@(\d{1,3})")
正規表現はオンラインの可視化サイト Regex101を見ながら作成するのが一番ミスがないかと。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
正解はumyuさんが書いておられるとおりでしょう。
()はその中に書いてある正規表現にマッチする部分を取り出すもの。そして\dは数字一文字にマッチするもの。
従って、(\d){1,3}では、()はその後に書いてある量指定子{1,3}のことなど気にもせず\dにマッチするものすなわち数字一文字を取ってきます。
()にマッチした部分文字列は\1とか\2とかで指定できるわけですが、この数字は開括弧が現れた順番に一致します。たとえばabcdefという文字列に対して(.).(.).((.).)という正規表現をマッチさせると、\1,\2,\3,\4にそれぞれa c ef e が入ります。試したこと①のようにすれば\0は無いので結果は空になるし、試したこと②のようにすれば当然333のような結果が返って来てしまいます。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 91.04%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2018/01/09 01:57
意図した数字を取得することができました。
迅速な対応本当にありがとうございます。
2018/01/09 01:59
明確な質問だったので、回答しやすかったです。