検索置換がらみで細々と
-
開発お疲れ様です。
某エディタを15年くらい使って来ましたが、色々あって先日からこちらを使わせていただいています。
いくつか、気になっているところがありますので投稿してみます。・ファイル検索の対象フォルダを固定できない
対象フォルダが常にアクティブなファイルのあるフォルダになってしまうのは、地味に使いづらいところです。・ファイル検索の対象フォルダを複数指定できない?
私が指定方法を判っていないだけかも知れませんが、某エディタでは
X:\hogehoge|Y:\mogemoge
という指定が可能です。・ファイル検索時、大量のファイル(検索対象外拡張子)があるフォルダでしばらく止まる
具体的には下位フォルダ合計で小さな画像を13万ほど格納しています。某エディタでは先に対象をリストアップするようで、数秒でファイル数が確定し、あっさりと終了します。・行選択時の置換で、置換元が$のときに余計な置換がなされる
ABCの$をDに置換する場合、期待値はABCDですが、Meryの場合次の行にもDが出てきます。
実は某エディタでも当初そういう挙動だったのですが、改善していただきました。正規表現ライブラリのデフォルト挙動、という話があった気がします。| mio | 返信 -
Mery をお試しいただきありがとうございます。
Mery は多機能系のテキストエディタとは異なり、初心者さんが簡単に使えるよう、細かい設定や複雑な機能を省いてシンプルなメモ帳をコンセプトに開発しています。
15 年以上の歴史があるテキストエディタと比べると全然機能が足りないと思いますので、引き続きそのエディタをお使いになられることをおすすめしますが、15 年使ったエディタを手放すのはよほどの事情がおありのようですね。
> ・ファイル検索の対象フォルダを固定できない
某エディタがどれなのかはわかりませんが、対象フォルダを固定できるものもありますね。> ・ファイル検索の対象フォルダを複数指定できない?
区切り文字が「|」ということで某エディタはあのエディタかなーとも思いますが、Mery では現在のところ複数指定は対応していません。> 具体的には下位フォルダ合計で小さな画像を13万ほど格納しています。某エディタでは先に対象をリストアップするようで、数秒でファイル数が確定し、あっさりと終了します。
Mery でも対象のファイルのみを検索していますし、バイナリや画像などは読み飛ばすことで高速化を図っており、これ以上の高速化の方法は思いつきません。きっと某エディタがスゴすぎるんだと思います。でも、リストアップなど高速化の具体的な方法がわかりましたら教えていただけると助かります。
> ・行選択時の置換で、置換元が$のときに余計な置換がなされる
> ABCの$をDに置換する場合、期待値はABCDですが、Meryの場合次の行にもDが出てきます。
ほんとですね、これは厄介ですね。私の技術力で対応できるかわかりませんが、調査してみようと思います。頂いたご意見は今後の開発の参考にさせていただきたいと思います。
| Kuro | 返信 -
横から失礼します。
> ・行選択時の置換で、置換元が$のときに余計な置換がなされる
> ABCの$をDに置換する場合、期待値はABCDですが、Meryの場合次の行にもDが出てきます
について、見当違いだったらごめんなさいですが、ABC\n の行を「行番号のクリック」や「行内でトリプルクリックし」て選択状態にしているときに
ABCD\n
D ...
となるということが mio さんのご指摘になっているところでしょうか?「行選択」で行末の改行記号が選択範囲に含まれている状態から置換を実行しているのでしたら、次の行の行頭が ^$ のかたちで $ にマッチするのでとくに不自然ではないとおもいます。末尾の改行をはじく必要がありますので、
・トリプルクリックでの行選択でしたら選択範囲末尾(次行の行頭)にキャレットがあるので、置換を実行する前に Shift+左カーソルキーで選択範囲を1文字分縮める
・行番号のクリックだと置換対象の行頭にキャレットがありますが、行末の改行記号も範囲に含まれているはずなので、https://www.haijin-boys.com/discussions/4431#discussion-4444 のようなマクロを利用する
・あるいは次行の行頭が置換されないような正規表現を使うとか e.g. (.)$ → $1D
…この正規表現だと空行をふくめた複数行のすべての行末に D を入れたい場合には適切ではありませんけど :|
・行選択しないで「次を検索」「置換」にすれば、次の行の行頭を巻き込むこともありません| sukemaru | 返信 -
ご意見ありがとうございます。
そう言われてみると確かに。行末の改行記号を含めている状態から置換している場合、次の行の行頭が $ にマッチしても間違いではないですね。
参考のため、ほかのテキストエディタの動作をチェックしてみました。
前提として…
1|ABC↓ 2|←
一応、1| 2| は行番号の部分、↓ は \n で、← は [EOF] です。
これのテキストを 1 行目を行選択、つまり "ABC↓" まで選択した状態で、検索文字列「$」置換文字列「D」で [選択した範囲のみ] オンで置換します。
結果として、いくつかパターンがありました。
まず、mio さんのご希望の動作になるもの。
1|ABCD↓ 2|←
・サク〇エディタさん
・秀〇エディタさん
・E〇Editor さん
・gP〇d さん
・Visual Studio CodeMery と同じ動作のもの。
1|ABCD↓ 2|D←
・Mery
・Sublime Textなんだこれ?なもの。
1|ABC↓ 2|D←
・Visual Studio 2019
絶望的なもの。(そもそも $ で置換できない)
1|ABC↓ 2|←
・Delphi 10.3
憧れのテキストエディタ Sublime Text と同じでちょっと嬉しくなりましたが、Mery の開発方針 (なるべく有名どころに合わせるスタイル) からすると、mio さんの仕様が良さそうですね。
技術的にどうすればよいのか分からないのですが… ^^;
| Kuro | 返信 -
追伸ですが…。
ちょっと納得のいかない事態になりました。・サク〇エディタさん
・秀〇エディタさん
・E〇Editor さん
・gP〇d さん
・Visual Studio Code↑ これらの仕様に合わせようかと思ったのですが、これら、[選択した範囲のみ] オンの状態なら合ってるんです。
でも、[選択した範囲のみ] がオフだとなんか挙動が異なるようで。
最初に申し上げた前提…
1|ABC↓ 2|←
で、[選択した範囲のみ] オフ (ここがポイント) で検索文字列「$」置換文字列「D」ですべて置換するとおかしいんです。
・サク〇エディタさん
・秀〇エディタさん
・E〇Editor さん
・gP〇d さん1|ABCD↓ 2|←
・Visual Studio Code
1|ABCD↓ 2|D←
となるようで、個人的には Visual Studio Code の挙動が正解なのではないかと思うのですが…。
| Kuro | 返信 -
検証おつかれさまです。
うちのスローな XP に不可をかけながら gPad でためしたら、「置換」を押した瞬間にキャレットが C のうしろに移動して、D をつけたしてから次の行頭に復帰するのを見て取ることができました。 :Dそれはそれとして、動作仕様の変更についてですが、「置換」パネルの「選択した範囲のみ」にかぎってのことでしょうか?
正規表現の解釈を変えてしまうということにもなりますし、場合によっては(Mery での)いままでの正規表現の書き方どおりでは文書最終行の空行 ^[EOF] にたいして置換をかけられなくなってしまいそうですね。
私の場合は Mery を使い出してから正規表現を勉強しはじめたので他のエディタのことはよくわかりませんが、 改行の次の行頭が ^$ であることが不自然だとはおもったこともありませんでした…。 :?あるいは、行番号のクリックやドラッグで行選択したとき全般で「さいごの改行」を暗黙的に無視するような方向でご検討でしょうか?
先のレスに貼ったリンク先のようなコードで選択範囲・論理行の末尾調整をしているマクロの動作が変わってしまうようでしたら、ちょっと困ったことになりそうな。
別トピックでは「なんでわざわざマクロでインデント/逆インデントなんてやってるの?」みたいに言われましたが、あれはあくまでも複数行の文字列一括操作の一例に過ぎないですから…。
「今後は末尾調整の仕組みを入れないで大丈夫」という前向きな考え方もできなくはないですが、テキスト操作、行操作・ソート・整形、コメントアウト系など、既存のマクロも結構な数がありますので、影響しない方向でご考量をお願いしたいところです。| sukemaru | 返信 -
> ・サク〇 ~ gP〇d さん
やっぱり文書末尾の空行 ^[EOF] では $ がマッチしなくなるというかんじでしょうか。> 個人的には Visual Studio Code の挙動が正解なのではないかと思うのですが…。
そんな気がしますが、私としてはいまの Mery の挙動のほうがが正規表現の解釈の仕方としては正しいようにおもいます。
たしかに「行選択したら『さいごの改行』は自分で工夫して除外してね」というのは不便を感じなくもないので、うまく折り合いがつくことを祈るばかりです。…というか正規表現入門者の私などが意見すべきところじゃないだろ、っていう。
| sukemaru | 返信 -
ご返信ありがとうございます。
> うちのスローな XP に不可をかけながら gPad でためしたら、「置換」を押した瞬間にキャレットが C のうしろに移動して、D をつけたしてから次の行頭に復帰するのを見て取ることができました。 :D
gP〇d さんそんなに重いですかー?そういえば gP〇d さん、つい先日、開発を再開されたようで、最新版では独自実装のスクロールバーでスクロールバーマーカーに対応されてました。そろそろ Mery も引き際ですねぇ。
> あるいは、行番号のクリックやドラッグで行選択したとき全般で「さいごの改行」を暗黙的に無視するような方向でご検討でしょうか?
最初はそう思ったのですが、sukemaru さんのおっしゃるとおり、改行を含めてるわけだから、間違いじゃないよね。って思っています。
> 「今後は末尾調整の仕組みを入れないで大丈夫」という前向きな考え方もできなくはないですが、テキスト操作、行操作・ソート・整形、コメントアウト系など、既存のマクロも結構な数がありますので、影響しない方向でご考量をお願いしたいところです。
分かります。正規表現やマクロ仕様などは既存のものへの影響が大きいですから、私もできるだけしたくはないですね。
> …というか正規表現入門者の私などが意見すべきところじゃないだろ、っていう。
私も正規表現のことはほとんどわからないので、正規表現の仕様はすべて知人にお願いしています。| Kuro | 返信 -
ご返信ありがとうございます。
> 引き続きそのエディタをお使いになられることをおすすめしますが、
むしろ高機能化が、気になりはじめていたという側面もあります。
機能面では必要なものは貴エディタで不足はなく、感謝しています。
バレバレですが、マクロがほぼそのまま動作するのも、乗り換えのポイントでした。> 某エディタがどれなのかはわかりませんが、対象フォルダを固定できるものもありますね。
> 区切り文字が「|」ということで某エディタはあのエディタかなーとも思いますが、Mery では現在のところ複数指定は対応していません。
これらについては、もちろん今後実装されると嬉しいなということでした。> Mery でも対象のファイルのみを検索していますし、バイナリや画像などは読み飛ばすことで高速化を図っており、これ以上の高速化の方法は思いつきません。きっと某エディタがスゴすぎるんだと思います。
失礼いたしました。そうすると何か鍵になる方法があるようですね…。> ほんとですね、これは厄介ですね。私の技術力で対応できるかわかりませんが、調査してみようと思います。
こちらについてですが。
すみません、某エディタでお願いしたのもかなり前の話だったので忘れていたのですが、行選択である必要はありませんでした。
単に「選択範囲の末尾を行末と扱っている」だけのようです。
行の途中を選択して$→Dで、Dが挿入されます。かたや^→Dとしても、Dは挿入されません。
| mio | 返信 -
書き忘れました。
回避策の「選択範囲の末尾を改行直前にする」はそのとおりで、実際そうしていました。
ただ、どうしても忘れがちですし、置換後に余計な文字(次行のD)があることに気づけば良いのですがそれも見落としてしまうことがありますので。| mio | 返信 -
ご返信ありがとうございます。
ファイルから検索で「|」区切りによる複数フォルダ指定につきましては検討させていただきたいと思います。
対象フォルダを固定する機能については、人それぞれ好みがありそうですから難しいところですね。
それに加えて、複数フォルダ指定や対象フォルダの固定のユーザインターフェイスも難しいところです。
某エディタの場合、[>] ボタンをクリックして、そこから [フォルダを参照]、[フォルダを参照して追加]、[固定フォルダ] みたいなメニューをさらにクリックとなっていますが、現状の Mery のように [...] ボタンの 1 ステップでフォルダ選択ができる点はマウスでもキーボードでも操作性が良いので…。
複数フォルダを指定するケースよりも 1 つのフォルダを指定するケースのほうが多いと思いますし、状況に応じて固定フォルダやアクティブな文書のあるフォルダなどに切り替えるケースもそれほどないと思いますので、操作が 2 ステップになってしまうのは微妙なところですね。
何か良い案があればよいのですが。
> 単に「選択範囲の末尾を行末と扱っている」だけのようです。
> 行の途中を選択して$→Dで、Dが挿入されます。
ご確認いただきありがとうございます。
選択範囲の末尾を行末として扱うのは間違いではなさそうですね。正規表現の仕様変更につきましては、多くのユーザさんに迷惑がかかりそうなので、ご不便をおかけして申し訳ございませんが、現在のところはご容赦いただければ助かります。
| Kuro | 返信 -
ご検討いただきありがとうございます。
> 対象フォルダを固定する機能については、人それぞれ好みがありそうですから難しいところですね。
現在の私の使い方では対象フォルダはほぼ固定のため、grepのたびに特定のファイル(検索開始ルートにあるファイル)をアクティブにしてからctrL+shift+fがやはり煩わしく感じます。食い下がって済みません。案としては、当該ダイアログでなくオプション画面に「フォルダを固定する」チェックを設置、です。
選択範囲の末尾についても同様で…というよりも、こちらは更にオプション向きだと思っています。
不具合でも回避手段がないわけでもありませんので、検討事項としておいていただけるだけでありがたいです。
※^は引っかからないのに$が引っかかるのは、不具合とは言わないまでも問題のある仕様だと思っていますが。
| mio | 返信 -
ご返信ありがとうございます。
> 食い下がって済みません。案としては、当該ダイアログでなくオプション画面に「フォルダを固定する」チェックを設置、です。
オプションで用意するのは開発側としても楽ではあるのですが、Mery はシンプル志向でなるべくオプション項目を増やさない開発方針ですので、ご要望が多ければ検討させていただきたいと思います。対象フォルダがほぼ固定ということでしたら、コマンドラインオプションの「/fd」を使うとフォルダを指定してファイルから検索ダイアログを開くことができるようになっています。
"C:\Program Files\Mery\Mery.exe" /fd "C:\Temp"
コマンドラインオプションはコマンドラインからはもちろんですが、Mery のショートカットをコピーしてショートカットのファイルのプロパティから [リンク先] の項目に記入することでも使用できます。
| Kuro | 返信 -
> ※^は引っかからないのに$が引っかかるのは、不具合とは言わないまでも問題のある仕様だと思っていますが。
なるほど、ご指摘の状況がわかりました。ABC\n ␣\n [EOF]
の3行の文章で1行目を行選択した状態(トリプルクリックまたは行番号クリックで末尾改行を含める)から「置換」ダイアログで
・検索文字列: 「$」
・置換文字列: 「D」
・フラグ: 正規表現/選択範囲のみ
で実行した場合にも、2行目の「 ␣ 」(任意の文字列)の前に「D」が追加されてしまいますね。 → 直後が改行でなくても「$」は選択範囲の末尾にマッチ。
それにたいして、以下の文章でさいしょの ␣ を除いた ABC\n␣ を範囲選択して「^」を「D」に置換を実行しても「A」の前には「D」が入れられることなく、2行目の行頭しか「D」になりません。 ← 「$」の振る舞いが正しいなら「^」は選択範囲の先頭にもマッチするべき。␣ABC\n ␣\n [EOF]
現状だと「$」は「選択範囲の末尾 "と" 行末(改行のまえ)の "両方" にマッチ」、「^」は「行頭(改行のうしろ)"のみ" にマッチ」なので、正規表現の「^」「$」の解釈が「^」と「$」とで一様になっていないから問題アリではないか? というのが mio さんのご指摘になっている部分なんですね。
「^」と「$」が「① つねに行頭・行末だけを対象にする」のか、または「② 行頭・行末 プラス 選択範囲全体の先頭・末尾 両方を対象にする」のかが統一されていないのは正規表現の振る舞いとしては不具合っぽいかんじがしますので、これについては私もどちらかに統一するべきだとおもいます。 ノシ
「置換」における正規表現の動作仕様は 2.6.12 でも変更されていますので、いずれかに統一するのはアリではないでしょうか?
自家用マクロで selection.Replace() を使っている方には申しわけない気もしますが、現状の実装では mio さんのご指摘どおり不自然ですし、ふつうに「置換」ダイアログで正規表現を使用するさいに混乱してしまいそうですよね。
あるいは… 「③ 選択範囲が『複数行(\n を含んでいる)のとき』と『1行のみ(\n を含んでいない)のとき』とで振る舞いを変える」という方法もありそうですが(i.e. 複数行なら改行の前後のみ、1行なら選択範囲の先頭・末尾、みたいな)。※マクロを作るさいに利用している JScript(JavaScript)の正規表現のばあいは m フラグの有無で 「^」「$」の振る舞いを指定できますが、m フラグをつけて「行の途中から別の行の途中まで」の選択範囲を replace() したときは、選択範囲の先頭・末尾と行頭・行末両方にマッチします。← この場合 JavaScript 側が「選択範囲の先頭位置が行頭か」どうかを判別することはできないでしょうから「まぁ当然か」というところ。
とはいえ、エディタの「置換」の仕様として実装だとどうあるべきかが、なにが最適かなんて、Mery を使う前は正規表現を知らなかった私にはサパーリわかりません。 :?
私個人は JScript の m フラグの振る舞いに慣れてしまいましたけど、JavaScript やマクロを扱ったことのない人には JScript 方式や、「置換」パネルにチェックボックスを追加してそこに書ける長さでの説明だとわかりづらい仕様になってしまいそうですね。 :(
「置換」ダイアログに振る舞いを指定するオプションを追加できないのでしたら、他のエディタの振る舞いに合わせるか ① か ② の振る舞いに統一したうえで、あらためて「Mery 2.7.x ではこれが仕様です」とするのがよいのではないでしょうか? …先の Kuro さんの検証結果から推測するに、他のエディタに統一性があるかどうかは疑わしいかんじですが。 X)ref. 各種の正規表現リファレンスでの説明
Onigumo: https://raw.githubusercontent.com/k-takata/Onigmo/master/doc/RE.ja^ 行頭 $ 行末
(※ これだけかよ!? とおもったら「補記 1」に以下の記述あり)
(?m) ^ は改行の直後に照合する、$ は改行の直前に照合する
(※ Onigumo.dll を使うほかのアプリがないので (?m) オプションの有無でどう振る舞いが変わるのか確認していませんが、Mery では (?m) の有無、または (?m:^) と単なる「^」とで振る舞いが変わることはないようで、マクロの JScript 的に行の途中から始まる選択範囲の先頭に「^」をマッチさせることができませんでした。
「$」については、単なる「$」でも、 (?m) をつけて検索文字列を (?m)$ または (?m:$) とした場合でも、文字列「ABCEFG」の「ABC」を範囲選択して「選択範囲のみ」で「D」に置換した結果は同じ「ABCDEFG」となりました)Ruby: https://docs.ruby-lang.org/ja/2.5.0/doc/spec=2fregexp.html
^ 行頭にマッチします。行頭とは、文字列の先頭もしくは改行の次を 意味します。
$ 行末にマッチします。 行末とは文字列の末尾もしくは改行の手前を意味します。
(※ 私はプログラミングはサパーリな人なので、選択範囲文字列の先頭・末尾にマッチするのかどうかはわかりません)Perl: http://perldoc.jp/docs/perl/5.16.1/perlreref.pod#ANCHORS
^ 文字列(/m が指定されている場合には行)の先頭にマッチします
$ 文字列(/m が指定されている場合には行)の終端もしくは改行の前にマッチします
(※ http://perldoc.jp/docs/perl/5.14.1/perlre.pod にも説明があります)JScript: https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc392020%28v%3dmsdn.10%29
^ 入力文字列の先頭と一致します。RegExp オブジェクトの Multiline プロパティが設定されている場合、^ は '\n' または '\r' の直後にも一致します。
$ 入力文字列の末尾と一致します。RegExp オブジェクトの Multiline プロパティが設定されている場合、$ は '\n' または '\r' の直前にも一致します。
(※MDN の JavaScript 正規表現リファレンスでも MS の JScript と同様の振る舞いをするという説明になっていました)@ Kuro さん
あらためてご確認とご検討をおねがいします & 長文にて失礼しました。| sukemaru | 返信 -
ご意見ありがとうございます。
> あらためてご確認とご検討をおねがいします & 長文にて失礼しました。
確認してみましたが、おっしゃる通り、正規表現の仕様のようですね。正規表現の仕様をエディタ側でどのように実装すべきかは、ちょっと私には判断がつきません。
> 「置換」における正規表現の動作仕様は 2.6.12 でも変更されています
それは私の力ではなく、正規表現にとても詳しい知人からご提案頂いた仕様なんです ^^;本件は私のほうではわかりかねますので保留とさせてください。
| Kuro | 返信 -
ご返信、ありがとうございます。
> 本件は私のほうではわかりかねますので保留とさせてください。
了解しました。
> 正規表現にとても詳しい知人
とても詳しい方たちは魔法のようなことをやってのけますよね。すごすぎて読めないことが多いのですが…。あと、少しまえの話、gPad が重いのではなく、私のしょぼいPCでHD動画を再生しながら他の操作をすると「ふつうなら見えないもの」が見えるようになることがあるんです。むかしRPGでどうしても倒せないボスキャラをこれでやっつけました。 LOL
| sukemaru | 返信 -
> オプションで用意するのは開発側としても楽ではあるのですが、Mery はシンプル志向でなるべくオプション項目を増やさない開発方針ですので、ご要望が多ければ検討させていただきたいと思います。
ありがとうございます。はい、個人開発のアプリをどのような方向性で開発するかは開発者さんの一存ですから、あえてとは言えません。
これほどのものを無償で使わせていただけるだけでありがたいことですし(少し前にささやかながら「支援」させていただきましたが)。> 対象フォルダがほぼ固定ということでしたら、コマンドラインオプションの「/fd」を使うとフォルダを指定してファイルから検索ダイアログを開くことができるようになっています。
済みません、ここは誤解させてしまいました。
言ってみれば創作系のWebサイトを持っているのですが、あるHTMLを編集しながら、語句選択して他のHTMLやtxtをgrep、整合性を確認することが多いのです。
全部で1000以上のHTMLがあるので、常時開いているのは頻繁な更新が発生する10程度で、あとはgrep、という使い方です。ふとここまで来て、対象フォルダ指定でgrepダイアログを開くマクロが書けるなら、そしてそれをctrl+shift+fに割り当てられるなら、UIを変更しないでも実現可能なのでは、と思いつきました。
| mio | 返信 -
詳細なフォローとご検討に感謝します。
>エディタの「置換」の仕様として実装だとどうあるべきかが、なにが最適か
私自身開発者で、これまでも使って来た人間ではあるのですが、人それぞれの経験や使い方もありそうですね。
さすがに自分の求めるものが「正しい」とまでは言えません。> そこに書ける長さでの説明だとわかりづらい仕様になってしまいそうですね。 :(
ああ…多くのアプリ開発者が苦労されている点ですね…。> …先の Kuro さんの検証結果から推測するに、他のエディタに統一性があるかどうかは疑わしいかんじですが。 X)
とくにこういう局所的な違いは、開発側が意識している場合もしていない場合もあると思います…。こちらも、キーボードへの特定マクロの割り当てが可能なら、もしかして実現可能…?と思いました。
selection末尾が改行なら、選択範囲をひとつ狭めるような…。| mio | 返信 -
ご返信ありがとうございます。
> ありがとうございます。はい、個人開発のアプリをどのような方向性で開発するかは開発者さんの一存ですから、あえてとは言えません。
ありがとうございます。ご要望につきましては検討させてくださいね。却下というわけではないのでご安心ください。(MeryWiki の [開発室] のご意見・ご要望リストに入ってます)> これほどのものを無償で使わせていただけるだけでありがたいことですし(少し前にささやかながら「支援」させていただきましたが)。
ありがとうございます。いただいた開発支援は開発費、素材費、運用費などにあて、今後、より良いソフトになるようにしたいと思います。> 言ってみれば創作系のWebサイトを持っているのですが、あるHTMLを編集しながら、語句選択して他のHTMLやtxtをgrep、整合性を確認することが多いのです。
なるほど、そういう作業でしたらマクロで選択文字列から grep というのもアリかもしれませんね。対象フォルダ指定で grep ダイアログを開くというのはマクロのメソッドとして用意されていないのですが、代案を考えてみました。
(1) 選択文字列から対象フォルダ (固定) を検索するマクロ案
var s = document.selection.Text; if (s !== "") { editor.NewFile(); editor.FindInFiles(s, "C:\\Temp\\*.txt", meFindRecursive); }
文字列を選択した状態でマクロを実行すれば grep されます。また、マクロはキー割り当ても可能です。
"C:\\Temp\\*.txt" の部分は対象フォルダと検索する拡張子。meFindRecursive はサブディレクトリも検索する。必要ない場合は 0 指定です。
(2) 外部ツールで Mery を使う案
コマンドラインオプション /ff と [外部ツール] 機能を組み合わせることで選択文字列を指定フォルダから grep できます。外部ツールの設定で、
タイトル:任意
コマンド: C:\Program Files\Mery\Mery.exe
引数:/ff "$(SelText)" /fr "C:\Temp\*.txt"文字列を選択した状態で外部ツール (キー割り当て可能) を実行すればファイルから検索が呼び出せます。
コマンドは Mery.exe へのフルパス。引数 /ff はファイルから検索、"$(SelText)" には選択文字列が入ってきます。/fr はサブディレクトリも含む、"C:\Temp\*.txt" は対象フォルダと拡張子です。
参考画像: https://www.haijin-boys.com/wiki/images/5/55/find-in-files-1.png
(2) 外部ツールで findstr を使う案
そもそも Mery の grep 機能ではなくて Windows 標準の grep 機能を使うこともできます。外部ツールの設定で、
タイトル:任意
コマンド: %WinDir%\System32\findstr
引数:/n /s "$(SelText)" "C:\Temp\*.txt"
アウトプットバーを使用する:オン文字列を選択した状態で外部ツール (キー割り当て可能) を実行すれば grep (のような機能) が呼び出せます。
findstr の引数は /n が行番号表示、/s はサブディレクトリも含める、"C:\Temp\*.txt" は対象フォルダと拡張子をワイルドカードで指定です。ほかにも大文字小文字の区別や正規表現なども可能です。
findstr を使うと、アウトプットバーに grep 結果が表示されますが、ダブルクリックすればジャンプできます。
参考画像:https://www.haijin-boys.com/wiki/images/d/d7/find-in-files-2.png
とこんな感じで、どれか使えそうな方法があれば良いのですが、いかがでしょうか。
| Kuro | 返信 -
> 対象フォルダ指定でgrepダイアログを開くマクロが書けるなら、そしてそれをctrl+shift+fに割り当てられるなら、UIを変更しないでも実現可能なのでは、と思いつきました。
WshShell.CurrentDirectory = "c:\\hode"; でカレントディレクトリの指定とか、var $strPath = document.selection.Text;; WshShell.Run( "\"C:\\Program Files\\Mery\\Mery.exe\\" /fd \" + $strPath + \""); のような記述で「コマンドラインでファイルから検索・置換」の実行ができそうですね。
grep っていう機能をあまり理解できていないのですが、「外部ツール」でも作業フォルダの指定や変数パスの指定をすれば「コマンドラインでファイルから検索・置換」もいけるのかしら?> 詳細なフォローとご検討に感謝します。
ご指摘の部分と補足した内容に齟齬がなかったのでしたら幸いです。 :)
> >エディタの「置換」の仕様として実装だとどうあるべきかが、なにが最適か
私自身は正規表現の勉強をはじめたばかりの1年生ですので、まだまだあちこち探し回っては切り貼りしているのがほとんどでして、本件に口をはさむのも申しわけないような。
> ああ…多くのアプリ開発者が苦労されている点ですね…。
海外製ソフトン翻訳でも苦慮する部分なので、ちょっとだけ分かります。 :)> こちらも、キーボードへの特定マクロの割り当てが可能なら、もしかして実現可能…?と思いました。
> selection末尾が改行なら、選択範囲をひとつ狭めるような…。
さいしょのコメントに貼ったリンクに選択範囲の末尾調整のマクロ用関数 SelectLines() を貼ってあります。
対象ファイルが多いとのことですので、ブックマークを気にしないのでしたら JavaScript マクロで検索・置換するほうが速そうですね。| sukemaru | 返信 -
ああ、リロードせずに書き込んだら Kuro さん直々の詳しい説明が…。
| sukemaru | 返信 -
代替案のご提示ありがとうございます。
grepに関しては、案1のマクロをベースにまずまず満足いくものが作れました。
○prompt("", document.selection.text)として、検索語句をベースにしながらも変更(正規表現を加味、等)可能に。
○findInFiles()をループすることで複数フォルダ、複数拡張子に対応(1回で可能ならもっと良いですが)。案2、3ではやり方を見つけられませんでした。こちらはひとまずこれで解決とさせてください。
置換に関しては、選択範囲の調整はsukemaruさんが挙げてくださったSelectLines()で可能でした(ありがとうございます)。
ただ、1ステップ目で例えば末尾改行を外したつもりが外れてない、必要以上に外してしまう、といったミスは防げますが、そもそも1ステップ目を失念してしまうのは変えられないようですね。
置換前後の文字列も固定はされていませんし、これについては当面自力対処することになりそうです。| mio | 返信 -
上記の実験中
http://mylph.my.coocan.jp/test/error.jpg
http://mylph.my.coocan.jp/test/error2.jpg
というダイアログが数セット出現し、すべてOKするとそのまま落ちました。
先ほどもう一度同じことがありましたので、念のため報告させていただきます。発生する条件は判りませんが、外部ツール実行やマクロ実行ではなく、キー割り当て変更(ctrl+shift+fを何度も変更)に関連しているのではないかと考えました。
| mio | 返信 -
ご返信ありがとうございます。
解決しそうとのことで安心しました。が…エラーにつきましては、恐らく [ファイルから検索] や FindInFiles メソッドがマルチスレッドで動作する仕様となっていますので、それを for ループから連続で呼び出すと、同時に複数の FindInFiles が発動してしまうので動作不良となっているのだと思います。
これに対応するためには内部仕様の大幅な変更が必要となりますので、しばらく時間がかかりそうです。
ご不便をおかけして申し訳ございませんが、現時点では FindInFiles を連続呼び出ししないようにしていただくしか対策がない状態です。
一応、FindInFiles は複数拡張子には対応しています。
editor.FindInFiles(s, "C:\\Temp\\*.txt;*.pas", meFindRecursive);
このように拡張子部分を「;」で区切ります。
でも、複数フォルダ指定には対応していませんから、ループで FindInFiles が使えないとなると問題ですね。
一つアイデアを思い付いたのですが、Mery の標準機能の [ファイルから検索] の仕様を以下のようにするというのはいかがでしょうか?
---- [ファイルから検索] の仕様変更案 ----
まず、「|」区切りによる複数フォルダ指定には対応します。[検索するフォルダ] の [...] ボタンの挙動はそのままなので、複数フォルダを指定する場合は手動で入力していただく必要があります。
で、フォルダの固定ですが、「|」による複数フォルダ指定がされている場合は、手動で入力されたと判断できますので、その値を保持します。(アクティブな文書のフォルダで上書きしない)
手動で入力した値が保持されるのは仕様としても違和感がないと思いますので。
これだとオプションを増やしたり、現状のユーザインターフェイスも変更することなくご希望の動作が実現できるような気がします。
ただ、問題がひとつありまして、複数フォルダを指定しない (「|」が使われていない) ときにフォルダを固定したいケースですが、この時は "C:\Temp|" みたいな感じでお尻に「|」を付けてもらうことになります。
--------正規表現置換の仕様変更につきましては、こちらの事情で恐縮ですが私の判断だけでは対応が厳しいので一旦保留とさせてください。
| Kuro | 返信 -
> エラーにつきましては、恐らく [ファイルから検索] や FindInFiles メソッドがマルチスレッドで動作する仕様となっていますので、
そういうことでしたか…。
完了してしばらくしてから発生するもので、思い至りませんでした。
FindInFiles()の終了を待てるI/F(たとえばWindow.findingやWindow.threadStatus)は、リファレンスを見る限り現状なさそうでしょうか。あるいは引数にコールバックを渡したり…。幸い常用したいフォルダは2つで、かつ他方からのgrepは毎回でなくて良いので、ご教示いただいた複数拡張子対応の上、検索語句の末尾に,を追加したら他方を探しに行くようにしました。
2回にはなりますが、これだけでもずいぶん手間は減りますし、当面は割り切ることにします。> ---- [ファイルから検索] の仕様変更案 ----
ありがとうございます。> [検索するフォルダ] の [...] ボタンの挙動はそのままなので、複数フォルダを指定する場合は手動で入力していただく必要があります。
「フォルダを参照」ダイアログは、自前のものでしょうか?
ここにチェックを追加して、現在指定されているパスに「追加する」ことができれば…とも思いましたが、さすがに変則的ですね。
大半の方には無意味なオプションになりそうですし。> これだとオプションを増やしたり、現状のユーザインターフェイスも変更することなくご希望の動作が実現できるような気がします。
確かにこちらの希望がすべて包含されていそうです。
ただ、こちらとしては、|がFindInFilesでも指定可能になるなら、上書きは従前でも大丈夫です。
一方的な希望で貴エディタに変則的な挙動を組み込ませてしまうのは忍びないですし、マクロで可能ならマクロで良いと思います。> 正規表現置換の仕様変更につきましては、こちらの事情で恐縮ですが私の判断だけでは対応が厳しいので一旦保留とさせてください。
了解しました。同じ要望をされる方がどれだけいるかも判らないお願いに、丁寧にご対応いただいていることに改めて感謝します。
| mio | 返信 -
ご返信ありがとうございます。
> FindInFiles()の終了を待てるI/F(たとえばWindow.findingやWindow.threadStatus)は、リファレンスを見る限り現状なさそうでしょうか。あるいは引数にコールバックを渡したり…。
はい、現状、そうった機能はないですね。
マクロは Windows のスクリプトエンジンを呼び出しているだけなので、スクリプトエンジン側から Mery のスレッドの終了を待つとなると技術的に難しそうですね。やるとしたら FindInFiles を別スレッドではなくてマクロと同じスレッドで動かして、grep 中はフリーズしたみたいになるけど我慢してね、な方式かな。と。
> 2回にはなりますが、これだけでもずいぶん手間は減りますし、当面は割り切ることにします。
お手数をおかけして申し訳ございません。> 「フォルダを参照」ダイアログは、自前のものでしょうか?
> ここにチェックを追加して、現在指定されているパスに「追加する」ことができれば…とも思いましたが、さすがに変則的ですね。
[フォルダを参照] は Windows 標準のダイアログなので独自オプションの追加は難しいと思います。恐らく、某エディタさんも苦肉の策で [>] ボタンによる 2 ステップにされたのだと思いますので、独自ダイアログを作成するよりは某エディタさん方式のほうが開発は楽ですね。> ただ、こちらとしては、|がFindInFilesでも指定可能になるなら、上書きは従前でも大丈夫です。
私も最初は FindInFiles で複数フォルダを指定できる仕組みを作る方向で検討していたのですが、現状の FindInFiles メソッドでは仕様を決められなかったのです。フォルダと拡張子を 1 つの文字列で指定する仕組みになっているので、複数拡張子だとこうなります。
editor.FindInFiles(s, "C:\\Temp\\*.txt;*.pas", meFindRecursive);
そうすると、複数拡張子 + 複数フォルダだと、
editor.FindInFiles(s, "C:\\Hoge\\|C:\\Temp\\*.txt;*.pas", meFindRecursive);
というのもおかしいし、
editor.FindInFiles(s, "C:\\Hoge\\*.txt;*.pas|C:\\Temp\\*.txt;*.pas", meFindRecursive);
というのもなんだかおかしい。(…おかしくない?これが無難かな…?)
参考のため某エディタさんのマクロ仕様を見てみたら、複数フォルダには対応していませんでした。そこで思いついたアイデアが [ファイルから検索] の例の仕様です。
> 一方的な希望で貴エディタに変則的な挙動を組み込ませてしまうのは忍びないですし、マクロで可能ならマクロで良いと思います。
「|」区切りによる複数フォルダ指定はできたほうが便利だと思いますし、今までなかった機能ですから、機能追加してもユーザさんには影響はないと思います。「|」が含まれていたら固定するっていう仕様はちょっと特殊ですが、そもそも「|」を知らない人には影響がないことと、別途特殊なオプションを設けるよりは将来的に某エディタさんのように「>」ボタンから細かいオプションを選択する方式にしたくなったときに移行がしやすいというのもあります。
> 同じ要望をされる方がどれだけいるかも判らないお願いに、丁寧にご対応いただいていることに改めて感謝します。
いいえー。FindInFiles が使えないのは Mery の仕様上の問題ですし、すぐには対応できそうにないので、代わりに何らかの対策ができればと思いまして。FindInFiles で複数フォルダの指定方法の仕様があれ (一番最後のヤツ) でよければできそうですけど…。
| Kuro | 返信 -
諸々、ありがとうございます。
以下、スクリプトの実装を知らないため好きなことを書いてしまいます。
|で区切らず、配列あるいはコールバックを渡せないかなと考えました。
複数の型を受け付ける仕様は、それなりにあると思いますので。
特定の定数を渡して、末尾に新規で可変引数というのも思いつきましたが、これも変則的かつ可変引数が可能かどうか。無理ということであれば、提示してくださった2つ目でしょうね。
気になる点があるとすれば、「UIでも将来的に、パスごとにフィルタを渡せるように」なんて話にならないかなと…。
そこは割り切りでしょうか。| mio | 返信 -
横から失礼します。
私は正規表現が大好きというか、ほぼマニアです。
私がこの置換をするならば、何人の方が言うように選択範囲を変えるよりは、まずは、以下のように置換しますね。検索する文字列:^(.*$)
置換後の文字列:$1Dこれで意図したとおりにいけると思います。意図したところに文字を「挿入」したいときは、「捕獲」の機能が枯れてますので、お薦めします。WinとLinuxの実装の違いも、回避しやすいですからね。
(sukemaruさんが書きたかったのは、こういうことですよね?)----------------------------------------
ところで置換の仕様について
「行選択時の、最終行の後の次にくる行頭を行末と扱うかどうか」は実装の上では正規表現の問題になるかもしれません。
しかし、そもそもの問題は、Windows系とLinux系の「【行選択そのもの】の仕様やイメージの違い」に由来していますよね。PerlはUnisysで始まり、その正規表現はLinux系で発達を遂げてきました。LinuxのVIなどを含むエディターでの行選択モードは、各行の「行頭から行末」までを選択しますから、「最後の選択行の、次の行の先頭」が選択文字列に含まれません。
対して、Windows系の多くのエディターでは、行選択とは、マウスカーソルの向きが変わるところでの選択を意味するため、次の行の先頭が選択範囲に含まれてしまいます。
つまり「行選択機能のイメージ=選択される範囲」がWindowsとLinux系で異なります。
行選択(とされている)範囲が異なるのだから、行選択をしたときにエディターが「ライブラリに渡す、【置換対象範囲】」は、Linux系で培われた理屈とは分けて、別の範囲を置換対象範囲として渡して欲しい」、という風に要望を考えれば、スレ主さんの主張は、正当に見えます。
繰り返しになりますが「どこまでを選択範囲としてライブラリに渡すか」が問題なのであって、「正規表現」の扱いの問題ではない気がしませんか。その上で既存のマクロへの影響範囲は考慮して、このままという選択肢もありでしょうが、それは消極的な気がしてしまいました。
このエディターにおいての「行選択」の定義の問題なのかなと。
-----
追伸
上記の置換の例は、どちらの行選択においても、正常に機能するように書いています。| tak | 返信 -
ありがとうございます。
どちらでも正しく置換する指定がある、というところは理解できるのですが、そして大抵の場合行選択して置換していることも確かなのですが…。
可能な限り単純に作業を進めたいですし(前後文字列を固定した専用マクロを複数作る手もありますが)、
話として途中から、選択範囲の後に空でない行がある場合、さらには選択範囲の末尾が行の途中の場合(行選択ですらない場合)を含んでおり…。最終的には「選択範囲の末尾は行末なのか」という話に変わっており、その意味ではどうなのだろうと悩ましく拝読させていただきました。
カーソルの位置は選択する方向により、選択範囲の末尾にあるとは限りませんし。済みません、日常的に正規表現を使ってはいますが、凝ったものは知識が追いついていませんし、歴史的経緯にも無縁です。
Aaa
bBBで小文字が選択されているとき、^と$はそれぞれどこだと捉えるのが正しいのでしょう。
個人的なイメージでは、^→行頭→bの前だけ、$→行末→aaの後ろだけ、なのです。| mio | 返信 -
mioさん
さきほど私が書いた内容の後半は、
「スレ主のmioさんの意見に賛成」というのを、
Kuroさんに(理由をつけて)伝えたつもりでしたが、伝わりましたでしょうか。その理由は長々と書いた通り、「Windowsの行選択はLinuxとは違うんだからさ」とうことです。
> Aaa
> bBB
>
> で小文字が選択されているとき、^と$はそれぞれどこだと捉えるのが正しいのでしょう。
> 個人的なイメージでは、^→行頭→bの前だけ、$→行末→aaの後ろだけ、なのです。これも賛成です。ちなみにサクラエデ〇タでは、mioさんのイメージする内容になっていますね。
| tak | 返信 -
> さきほど私が書いた内容の後半は、
> 「スレ主のmioさんの意見に賛成」というのを、
> Kuroさんに(理由をつけて)伝えたつもりでしたが、伝わりましたでしょうか。
はい、もちろんそれは伝わっており、ありがたく思っています。ただ、話の中心が「行選択」から離れた後でしたので、そこについての有識者のご意見も伺いたく思ってしまい…ご気分を害されたとしたらお詫びします。
> これも賛成です。ちなみにサクラエデ〇タでは、mioさんのイメージする内容になっていますね。
はい、作者様の最初のコメントでもそのようにあり、国内の主要なエディタは皆そうなるようだ、と考えています。
ちなみに○clipseは、「$」一文字では置換させてくれませんでした…。何れにしても最終的には作者様の目指すところ、ご判断ですので、それを尊重させていただこうと思っています。
| mio | 返信 -
>> tak さん
ご意見ありがとうございます。> 繰り返しになりますが「どこまでを選択範囲としてライブラリに渡すか」が問題なのであって、「正規表現」の扱いの問題ではない気がしませんか。
そうですね、私の表現が良くなかったようでお詫び申し上げます。正規表現ライブラリの問題ではなく、エディタ側の実装次第ということで、正規表現ライブラリにエディタ側がどういった値を渡すかという問題であることは把握しております。
Mery の正規表現置換に関する仕様変更につきましては、tak さんのご意見もあわせて検討させていただきたいと思います。
>> mio さん
ファイルから検索の件ですが、ご返信ありがとうございます。ほんとですね…、おっしゃる通りでした。
パスごとにフィルタを渡すとなると、そもそも現在の機能では対応していないわけで、その点をすっかり見落としていました。> |で区切らず、配列あるいはコールバックを渡せないかなと考えました。
> 末尾に新規で可変引数というのも思いつきましたが、これも変則的かつ可変引数が可能かどうか。
ご提案いただきありがとうございます。
マクロから配列渡しは以前にも研究したことがあるのですが、情報がまったくなくて実装することができませんでした。Delphi と ActiveScript で配列をやり取りする方法が分かる方がいらっしゃったら情報を頂けると助かります。(と、何度か書き込みしましたけど、なさそう…)引数の数が可変というのも難しそうですね…。
そして、パスごとにフィルタが無理となると、残された方法は FindInFiles の終了待ちを実装するという正統派な作戦になりますが、恐らく変則的なマクロ仕様を研究するよりは、正統派な作戦のほうが開発時間は短くて済みそうなので、FindInFiles の仕様は現状通りで、終了待ちを実装するための研究のほうを中心に進めていきたいと思います。
アイデアを頂けたおかげで色々とシンプルな形で整理できまして、形が見えてきました。ありがとうございます。
| Kuro | 返信 -
詳しく分かりやすいご説明をいただき、ありがとうございます。
> 検索する文字列:^(.*$)
> 置換後の文字列:$1D
便利な正規表現サンプル! ありがとうございます。
行頭の置換「D$1」、行末の置換「$1D」、行頭・行末の置換で挟み込み「D$1D」と応用がきくので、これは一粒で三度おいしいですね。 :D> Aaa
> bBB
の例については、私は逆の意見です。
「選択範囲のみ」フラグを有効にしている場合にかぎっては、渡した選択範囲にたいして正規表現側に選択範囲外の \n の有無を判断させるのは不自然な気がします。
前出の Perl や Ruby の説明にあるように「^/$ の適用は選択範囲の先頭/末尾(もふくむ)」仕様で、ユーザー側が意識的に選択範囲を区切って「置換」コマンドの正規表現に渡すほうがよいのではないかと。
当座は保留案件ということになりましたので、将来的にどちらかのかたちで統一されるのでしたらどちらでも…。 :)| sukemaru | 返信 -
かなり乗り遅れた感がありますが、「ファイル検索の対象フォルダを固定」に一票を投じておきます。
| Dainty | 返信 -
諸々ご対応ありがとうございます。
2.7.6にアップデートした上で終了待ち版FindInFilesを使ってみました。
editor.newFile();
for (var i=0, f; (f = fs[i]); ++i) {
editor.FindInFiles(s, f + "\\*.htm;*.html;*.txt;*.doc", meFindRecursive || meFindReplaceRegExp);
}
1つ目でヒットがあっても、2つ目に移った瞬間すべてクリアされますね。
UI版で | を使えるようにしていただけたので、ひとまずこれはこれで良いのですが、少し気になりました。| mio | 返信 -
ご確認ありがとうございます。
> editor.newFile();
> for (var i=0, f; (f = fs[i]); ++i) {
> editor.FindInFiles(s, f + "\\*.htm;*.html;*.txt;*.doc", meFindRecursive || meFindReplaceRegExp);
> }
> 1つ目でヒットがあっても、2つ目に移った瞬間すべてクリアされますね。
はい。これは本バージョンからの仕様というわけではなく、もともと FindInFiles は編集中の内容を破棄してファイルから検索モードに入る仕様です。
某エディタもそうなっていますね。ファイルから検索で結果が表示されている状態 (ファイルから検索モード) は通常の状態とは異なり、タブのタイトルが検索文字列だったり更新状態が新規の状態だったり、ダブルクリックでファイルへ移動したりします。
これらの理由からファイルから検索は 1 度の実行で 1 つのタブを占有しますから、編集中の内容を破棄する仕様のほうが都合が良いのだと思います。なので、やるとしたら、
for (var i=0, f; (f = fs[i]); ++i) { editor.newFile(); editor.FindInFiles(s, f + "\\*.htm;*.html;*.txt;*.doc", meFindRecursive || meFindReplaceRegExp); }
こんな感じで editor.newFile(); を中に入れてやってそれぞれ新しいタブに対して出力するか、
1 つのタブの中で完結させたいなら、
var s = ""; editor.newFile(); for (var i=0, f; (f = fs[i]); ++i) { editor.FindInFiles(s, f + "\\*.htm;*.html;*.txt;*.doc", meFindRecursive || meFindReplaceRegExp); s += editor.activedocument.Text; } editor.activedocument.Text = s;
こんな感じで変数 (s) の中に一時的に結果をためて置いて、最後にドキュメントの内容をそれに置き換えれば良いかと思います。(この場合、タブのタイトルの検索文字列の部分は最後の FindInFiles の検索文字列になります)
| Kuro | 返信 -
ありがとうございます。
> 某エディタもそうなっていますね。
失礼しました、これは確認していませんでした。ともかくも、grepについては期待の動きにしていただきました。
ご対応ありがとうございました。| mio | 返信 -
選択範囲の末尾を行末として扱っている件ですが、検討させていただいた結果、やはり現状の仕様を変更するのは影響範囲が大きいかもしれないことと、正規表現エンジン (鬼雲) の標準仕様ということで、現状ではとりあえずデフォルトはこのままとさせていただきたいと思います。
隠しオプションというかたちになりますが、選択範囲の末尾を $ に一致させないようにする設定を用意してみますので、それで様子を見てみてくださいませ。
| Kuro | 返信 -
開発お疲れ様です。
今回の対応でこちらの希望はすべて叶えていただきました。
ご検討、ご対応に感謝します。| mio | 返信