ハトネコエ Web がくしゅうちょう

プログラミングやサーバー・Web制作、チームマネジメントなど得た技術のまとめ

Emacs の正規表現の置換・検索 ( RegExp replace or search ) を賢くかわいくしてあげよう

Emacs正規表現が上手く使いこなせない・・・。

いや、私が使いこなせないんじゃない! Emacs が悪いんだ!!
……と思ったので改造です。

頭おかしい! Emacs正規表現

Emacs正規表現は独特すぎて頭おかしいです。他のに慣れてると全然使いこなせません。

RegExp replace (正規表現での置換)のときも、
どの文字が正規表現に引っかかっているかわからず結果、
Replaced 0 occurrences
の一文を見てガッカリすることになります。

Emacs 標準搭載の Re-Builder という機能を使って、正規表現が一致するか見ることは出来ますが・・・*1
ちょっと例を見てみましょう。

使えない Re-Builder

	<p name="lemon">
	   lemon
	</p>
	<p name="melon">
	   melon
	</p>

これの name="" の中身をそれぞれ fruits-lemon, fruits-melon に置換したいと考えてみましょう。

で、M-x re-builder で Re-Builder を立ち上げて、
出てきた下の *RE-Builder* ボックスに入力して確認しましょう。

f:id:nekonenene:20150911214108j:plain

なるほど、emacs では \"\\([a-z]+on\\)\" と入力すればいいんだな。
ずいぶんバックスラッシュ多いんだな、と理解してこれで replace してみようとしてみます。

f:id:nekonenene:20150911221059j:plain

しかし現実は非情!!
そこには Replaced 0 occurrences の文字が!!

「Re-Builderくんの嘘つき!!」
と純真な少女っぽい言葉も叫びたくなります。

ちなみに正しくは、 "\([a-z]+on\)""fruits-\1" で置換できます。
わりとふつうです。

めんどくさいし引っかかりポイントな改行コード

正規表現の改行コードといえば、当然、バックスラッシュn、\n です。
Emacs はそうではありません。C-q C-j です。頭おかしいです。
ってか、私は C-TAB は next buffer への移動、C-q は previous buffer への移動にキーバインドしてるので、
C-q 押したとたんに違うバッファー(タブ)に飛ばされちゃうので使えません!!

公式の正規表現の案内のページには

You can enter a newline character using ‘C-o’, ‘C-q C-j’, or ‘C-q 012 RET’.

と書かれていますが、私の環境では C-o でダメでした。(なんかキーバインド振ってたっけ)

解決策1 : foreign-regexp を使おう

詳しくはこちらを : Emacs: re-builder + foreign-regexp.elでたのしい正規表現 | 葉月夜堂

ただし、そこでも書かれていますが、
Emacs のバージョンが 24.4 や 24.5 では

Wrong type argument: commandp, ad-Orig-foreign-regexp/query-replace

とエラーが出て使えません。

私のEmacsは最新の 24.5 にしてあるので同じエラーが出て使えませんでした。
Perl, Ruby, Python, JavaScript といったいろんな言語の正規表現形式に対応していて、良さそうだったんですけどね。
別な方法を考えましょう。

解決策2(本命) : visual-regexp-steroids を使おう

参考 : visual-regexp-steroids.el : 【正規表現革命】isearchや置換でPerl/Pythonの正規表現を使おうぜ!

導入が少し特殊なので気をつけましょう。

まず visual-regexp-steroids のパッケージをインストールします。
このとき、 visual-regexp のパッケージもインストールされると思いますが、
そちらも大事ですので、emacsプラグインを置いているフォルダにどちらも置いてください。

それから、pcre2el というパッケージもインストールしておくとよいでしょう。
これは、Python がインストールされていない(PATHが通ってない)パソコンで visual-regexp を使いたいときに必要になります。
私は複数パソコンでEmacsの設定を使いまわしているので、いちおう pcre2el はインストールしておきました。

さて、プラグインEmacsが読み取るフォルダーに置きましたら、
init.el (Emacsの設定ファイル)に以下のように書き足します。

(defvar emacs-root
  (eval-when-compile
    '(
      (require 'visual-regexp-steroids)
      )))
;; 上記のように書かないと、コンパイル時に `regexp-string' 由来の警告を吐く

(setq vr/engine 'python) ; 'python, 'pcre2el, or 'emacs
;; python が インストールされてない環境では、上1行をコメントアウト、下2行をコメント解除
;; (setq vr/engine 'pcre2el)
;; (require 'pcre2el)

;; multiple-cursors ( https://github.com/magnars/multiple-cursors.el ) を使っている場合は下1行をコメント解除
; (global-set-key (kbd "C-c m") 'vr/mc-mark)
;; 普段の 'query-replace-regexp を visual-regexp に
(define-key global-map (kbd "C-x C-r") 'vr/query-replace)

ふだんは (require 'visual-regexp-steroids) だけでプラグインを読み込むと思いますが、

~/.emacs.d/elpa/visual-regexp-steroids/visual-regexp-steroids.elc:Warning:
    reference to free variable `regexp-string'
~/.emacs.d/elpa/visual-regexp-steroids/visual-regexp-steroids.elc:Warning:
    reference to free variable `replace-string'

と Warning を吐いてうっとおしいので、上のように記述しておくことをオススメします。
*追記(2015/9/12 22:00):上記のように書いたのですが、これを記述するとそもそも visual-regexp が動かなくなることに気付いたのでやめてください。
ふつうに (require 'visual-regexp-steroids) で呼んでください。
起動のたびに *Compile-Log* のバッファが開いてちょっと嫌ですが、あきらめるしかないですかね。

visual-regexp-steroids を導入するとこうなる!

置換される箇所がハイライトされるから見やすい

f:id:nekonenene:20150911225809j:plain

正規表現に一致する部分がハイライトされます!

f:id:nekonenene:20150911225851j:plain

置換後にどうなるかを表示してくれます!

あとはいつも通り、y か n か ! を押して置換するだけです。

複数行の置換が簡単にできる

例えばこのように、

	<p name="lemon"
	>
	   lemon
	</p>

" と > が別の行に行ってしまってるので連結したい、としましょう。

f:id:nekonenene:20150911230033j:plain

そのときはウィンドウ下に出ているように、C-c mを押すと複数行検索になりますし、*2
ちゃんと \n も使えますので簡単に置換することができます。

f:id:nekonenene:20150911230721j:plain

f:id:nekonenene:20150911230730j:plain

f:id:nekonenene:20150911230742j:plain

ね! かんたんでしょ!

Emacs正規表現の融通きかなさに困ってる人、ぜひ visual-regexp-steroids を使いましょう。
これ無しの正規表現置換はしたくなくなりますよ!

ちなみに

私は正規表現を置換でしか使わないのでやっていませんが、
search でもこれを使いたい場合は、

(global-set-key (kbd "C-S-s") 'vr/isearch-forward)  ;; Ctrl + Shift + s で前方検索
(global-set-key (kbd "C-S-r") 'vr/isearch-backward) ;; Ctrl + Shift + r で後方検索
;; キーバインドはお好みで……

などと書いておけば OK です。

*1:Re-Builderについて : Emacs で正規表現を使うなら re-builder を使おう - higepon blog

*2:もしこのようにたくさんのメニューが出ていないときは、M-x vr/select-query-replace ののちに python と入力すると直るかと思います