1773


emacs(lisp)で、リージョン中の内容をre-search-forwardとreplace-
matchなどの組み合わせで置換していくときに、構文のfooは置換したいけれど、文字列中のfooは置換したくない、という場合は、どうするのが定石なのでしょうか。

[code]

    foo "foo" foo Foo
    => bar "foo" bar Foo
    
[/code]

という風に置換したい場合の定石があれば教えて下さい。


CC BY-SA 3.0
2014-12-16T08:07:57.593
1709
2014-12-16T13:25:17.577
2014-12-16T08:19:02.960
208
3510
question
emacs elisp
文字列中のアイテムを置換したくない場合の定石は?


ちょっと複雑ですが、正規表現の後読み `(?<=PATTERN)` や 先読み `(?=PATTERN)` を使えばできます。

emacs 標準の正規表現置換 `replace-regexp` は後読み・先読みが使えない ([ _Emacs does not support
Perl-style lookahead/lookbehind_](http://www.emacswiki.org/RegularExpression))
ので、`M-|` で起動する `shell-command-on-region` で Perl ワンライナを実行します。

  1. 置換したいリージョンを選択
  2. `C-u M-|` をタイプ
  3. Shell command on region: `perl -pe 's/(?<!")foo(?!")/bar/g'`

上記手順 2 の `C-u` は、選択中のリージョンを Perl の出力で置き換えるために必要な prefix argument
というものです。これをタイプしないと外部コマンドの出力は *Shell Command Output* バッファに出力されます。

emacs 標準の正規表現は機能不足であったりエスケープも面倒なので、手の込んだ置換をしたい場合には外部コマンドの正規表現を使うのがオススメです。


CC BY-SA 3.0
2014-12-16T13:09:18.810
1766
2014-12-16T13:14:55.593
2014-12-16T13:14:55.593
3158
3158
1709
answer


二重引用符に囲まれているものが syntax的に文字列として認識されているので あれば syntax-tableの情報を使うという手があります.
文字列内にいるか どうかは `syntax-ppss`の 4番目(index的には 3)が non-nilの場合, 現在文字列内にいるということになります.

これを使うと以下のようにすることで文字列中以外のところに **foo** だけ **bar** に置換することができます.

[code]

    (while (re-search-forward "foo" nil t)
      (unless (nth 3 (syntax-ppss))
        (replace-match "bar")))
    
[/code]

上述のとおり syntax-tableの情報を使うので, fundamental-mode等では 利用することができません.


CC BY-SA 3.0
2014-12-16T13:25:17.577
1773
2014-12-16T13:25:17.577
3521
1709
answer