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

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

ただいまの
回答率

90.86%

  • Python

    6296questions

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

  • Python 2.7

    1164questions

    Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

  • 正規表現

    728questions

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

  • Qt

    117questions

    QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

Pythonの正規表現で一致した文字列を再利用したいがうまくいかない

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 423

mofu_mofu

score 28

前提・実現したいこと

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で実行 → サンプルがすべて消える
イメージ説明

③サンプルを置換文字列\1\1\1で実行
イメージ説明

#③の結果
333
333
444
555
666

補足情報(言語/FW/ツール等のバージョンなど)

Windows10
Python2系

以上になりますがどうぞよろしくお願いいたします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

数字をマッチさせたいならこうでは?

regex = re.compile("@@@(\d){1,3}")


regex = re.compile("@@@(\d{1,3})")

正規表現はオンラインの可視化サイト Regex101を見ながら作成するのが一番ミスがないかと。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/09 01:57

    umyuさんのおっしゃるとおり```@@@(\d){1,3}```ではなく```@@@(\d{1,3})```でした。
    意図した数字を取得することができました。

    迅速な対応本当にありがとうございます。

    キャンセル

  • 2018/01/09 01:59

    解決おめでとうございます。
    明確な質問だったので、回答しやすかったです。

    キャンセル

+1

正解はumyuさんが書いておられるとおりでしょう。

()はその中に書いてある正規表現にマッチする部分を取り出すもの。そして\dは数字一文字にマッチするもの。

従って、(\d){1,3}では、()はその後に書いてある量指定子{1,3}のことなど気にもせず\dにマッチするものすなわち数字一文字を取ってきます。

()にマッチした部分文字列は\1とか\2とかで指定できるわけですが、この数字は開括弧が現れた順番に一致します。たとえばabcdefという文字列に対して(.).(.).((.).)という正規表現をマッチさせると、\1,\2,\3,\4にそれぞれa c ef e が入ります。試したこと①のようにすれば\0は無いので結果は空になるし、試したこと②のようにすれば当然333のような結果が返って来てしまいます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/12 16:07

    お礼が遅れてしまい申し訳ありません。
    \数字は何番目のカッコの内容を取得するのかという意味で、私が設定した()が一つしかないので\1以外意味なかったのですね。

    そして、量指定子が()外にあるので1個から3個までという意味が()に適用されていないのですね。

    大変勉強になりました。ありがとうございました。

    キャンセル

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

  • ただいまの回答率 90.86%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python

    6296questions

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

  • Python 2.7

    1164questions

    Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

  • 正規表現

    728questions

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

  • Qt

    117questions

    QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。