ダブルクオートで囲まれていない範囲で置換をしたい
こんにちは。大学生です。
ダブルクオートで囲まれていない範囲で置換をしようとして困っています。
一度の置換でなくて構いません。
vimで置換をしていまして、ソースコード中の/の前後に半角空白を入れる置換をしようとしています。
例としては「a/b」を「a / b」のようにしたいです。
以下、やってみたことです。
pythonにある切り捨て除算//は
a//
b を前もって別の文字列にして、
この処理の後にa//
bにする処理を入れます。
調べたところ「あいaうえお」を「あいbうえお」に置換するには
:%s/\(.*)a\(.*)/\1b\2/g
のようにすると良いとわかりました。
すでに前後に半角空白を実行ごとに増やさないようにしつつ、
いまこのような置換コマンドを作りました。
:%s;\([^\s/]\)\s*/\s*\([^\s/]\);\1 / \2;ge
わかりづらいので改行を入れますと、
:%s
ファイル全体を置換
;
区切りを;にする よくある:%s/a/b/g
を:%s;f;b;g
に
\([^\s/]\)
グループ\1 スラッシュと空白以外の文字
\s*
スラッシュの前にある0個以上の空白
/
目的のスラッシュ
\s*
スラッシュの前にある0個以上の空白
\([^\s/]\)
グループ\2 スラッシュと空白以外の文字
;
置換前と置換後の区切り文字
\1 / \2
グループ1と2で_/_を挟む
;ge
もしマッチしなくてもエラーを表示しない
しかしソースコード中にダブルクォートで囲まれたパスが存在するため、
このままでは「"/home/user/a.png"」が「" / home / user / a.png"」のようになってしまいます。
このため””で囲まれていない範囲で置換を行いたいです。
(シングルクォートはこの際無視します_(┐「ε:)_)
コードフォーマッタを使うといいと思われると思いますが、
ソースコードはCやPython,Haskellなど複数種類あり、
都合の良いコードフォーマッタがありません。
そのためvimのコマンドとして関数を定義し、
.vimrcに書き、必要な時に呼び出したいと思います。
ある程度の副作用はその都度コマンドを修正していき、
最終的には僕の考えた最強の/を置換するコマンド、
という微妙なものを作りたいと思います。
調べたところ、条件が異なる回答ではありますが
「かっこ[]で囲まれた文字以外をマッチさせたい」という質問の回答で
先読みを利用すれば出来ると思います。
マッチさせる箇所(A)を[^\[\]]+
、させない箇所(B)を\[[^\[\]]+\]
だとすると、先読みさせるにはA(?=B)、つまり[^\[\]]+(?=\[[^\[\]]+\])
という形になります。これと末尾(もしくは全体)にマッチするパターンA$=[^\[\]]+$
を組み合わせれば
([^\[\]]+(?=\[[^\[\]]+\])|[^\[\]]+$)
となります。
https://ja.stackoverflow.com/a/9032/31797
というのを見つけ、これを使えばうまくできるのではないかと考えています。先読みというのが初めてでvimの正規表現では
https://vim-jp.org/vim-users-jp/2009/09/20/Hack-75.html
http://d.hatena.ne.jp/unk_pizza/20140311/p1
を見て、条件となるパターン①とマッチさせたいパターン②の2つを用いてパターンマッチさせる方法であると理解しました。
(自信はありません_(┐「ε:)_)
私の場合、①でない全ての②を置換後文字列③にする否定先読み、否定後読みを用いるのが良いと考えました。
この場合、①条件となるパターンと、②マッチさせたいパターン、③置換後文字列は
①「""」で囲まれている文字列
②「/」 すでに前後に空白がある時はそれも含む
③「/の前の文字列」半角空白/半角空白「/の後の文字列」
となるのでしょうか。
ここから正規表現にするところで止まっています。
正規表現でダメだったら、1行読み込んで"があるかどうか判定、
"がなければ前述の置換、あれば"までの文字列と”の中の文字列、 "の後の文字列に分けて""以外の文字列に置換、というのを書こうと思います_(┐「ε:)_