正規表現置換を行う関数No.01706
IKKI さん 09/03/18 19:25
 
こんにちは。ユーザの IKKI です。

>  ただここまで一般的なら、単語検索が有っても良い気がします。
>  ##マクロを書く人なら、\<, \> を使うかもしれませんが。

賛同します。
ただ、もしやるとしたらの話ですが、秀丸の動作環境の
「単語の検索で "abc" を検索するとき "abc123" にはヒットさせない」
の影響を受けるのかどうか気になるところです。


それと、便乗して HmJre.dll に対する要望をひとつ…

Ruby の gsub() にあたる正規表現置換関数を追加していただけると大変ありがたい
です。

●利用イメージ

$self = "color = 0x123456;";
$search = " *= *0x([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2});";
$replace = "=\"#\3\2\1\"";
$result = ReplaceRegular($self, $search, $replace);
// "color=\"#563412\""

●マクロで同じことをするには

次のようにすればできますが、速度面でも手軽さの面でも不利だと感じています。

GSUBR:  // HmJre.dll による正規表現置換(後方参照可)
  // $$1 = 対象文字列
  // $$2 = 検索パターン
  // $$3 = 置換パターン
  // ##4 = 1:大文字小文字を区別する
  $$f = leftstr("FindRegularNoCaseSense", 11 + (##4 == 0) * 11);
  $$s = $$1;
  while (true) {
    ##p = dllfunc($$f, $$2, $$s, 0);
    if (##p < 0) break;
    $$t = "";
    $$u = $$3;
    while (true) {
      ##q = strstr($$u, "\\") + 1;
      if (##q <= 0) break;
      $$t = $$t + leftstr($$u, ##q - 1);
      ##e = ascii(midstr($$u, ##q, 8192));
      if (##e >= '1' && ##e <= '9') $$t = $$t + midstr($$s, dllfunc("GetLast
MatchTagPosition", val(char(##e))), dllfunc("GetLastMatchTagLength", val(cha
r(##e))));
      else if (##e == '\\') $$t = $$t + "\\";
      else if (##e == 'n')  $$t = $$t + "\n";
      else if (##e == 't')  $$t = $$t + "\t";
      else                  $$t = $$t + char(##e);
      $$u = midstr($$u, ##q + strlen(char(##e)), 8192);
    }
    $$r = $$r + leftstr($$s, ##p) + $$t + $$u;
    $$s = midstr($$s, ##p + dllfunc("GetLastMatchLength"), 8192);
  }
  if (##p == -2) message "正規表現のエラーです\n" + $$2;
  return $$r + $$s;

ということで、ご検討いただければ幸いです。

[ ]
RE:01706 正規表現置換を行う関数No.01707
秀まるお さん 09/03/19 17:45
 
 単語検索もやろうと思えば出来ると思いますが、秀丸エディタの処理とまった
く同じにするのはちょっと難しいかもしれません。

 それと、タグ付き正規表現を使った置換の処理もやろうと思えば出来ると思い
ます。

 ちょっと考えてみます。

[ ]
RE:01707 正規表現置換を行う関数No.01708
Iranoan さん 09/03/19 18:04
 
 秀まるおさん今日は、Iranoan です。
>  単語検索もやろうと思えば出来ると思いますが、秀丸エディタの処理とまった
> く同じにするのはちょっと難しいかもしれません。
>
>  それと、タグ付き正規表現を使った置換の処理もやろうと思えば出来ると思い
> ます。
>
>  ちょっと考えてみます。
 実装されるかどうかは別にして、御検討有難うございます。

 P.S
> それと、便乗して HmJre.dll に対する要望をひとつ…
>
> Ruby の gsub() にあたる正規表現置換関数を追加していただけると大変ありがたい
> です。
<snip>
に関しては、現在の方法は確かに繁雑ですが、マクロなので、よりプリミティ
ブな関数があるので十分だと思っています。

[ ]
RE:01708 正規表現置換を行う関数No.01709
秀まるお さん 09/03/27 14:38
 
 次の秀丸メールβ版に付属させるHmJre.dllのV1.98にて、以下の2つの関数を
追加しようと思います。

char* _cdecl ReplaceReguar( char* pszPattern, char* pszTarget, int
xStart, char* pszReplace );

extern "C" char* _cdecl ReplaceRegularNoCaseSense( char* pszPattern,
char* pszTarget, int xStart, char* pszReplace )


 使い方としては、

    message dllfuncstr("ReplaceRegular"
                , "([a-z]+)([0-9]+)"
                , "----abcdefg1234567----"
                , 0
                , "\\2\\1" );

 として呼び出すと、

      ----1234567abcdefg----

 が出てくる、みたいな感じですけど。

 これでいいですかね?

 あと、「単語の検索」については別に無くてもそんなに困らないと思うのでや
っぱりやめようかなぁと思ったりしています。

[ ]
RE:01709 正規表現置換を行う関数No.01710
Iranoan さん 09/03/28 14:23
 
 秀まるおさん今日は、Iranoan です。
> char* _cdecl ReplaceReguar( char* pszPattern, char* pszTarget, int
> xStart, char* pszReplace );
>
> extern "C" char* _cdecl ReplaceRegularNoCaseSense( char* pszPattern,
> char* pszTarget, int xStart, char* pszReplace )
 こちらについては、私はどちらでも良かったのですが(^^;、マクロの作成が
が随分楽にはなります。

>  あと、「単語の検索」については別に無くてもそんなに困らないと思うのでや
> っぱりやめようかなぁと思ったりしています。
 残念。

[ ]
RE:01709 正規表現置換を行う関数No.01711
IKKI さん 09/03/28 18:59
 
こんにちは。IKKI です。

>  これでいいですかね?

かなり良さそうです。どうもありがとうございます。

>  あと、「単語の検索」については別に無くてもそんなに困らないと思うのでや
> っぱりやめようかなぁと思ったりしています。

単語の検索は正規表現でやればよい、ということで理解しました。


--- 以下雑談 ---

正規表現で「(数字を含む) 単語の境界」を正確に表現するのはちょっと面倒で、
「(?<![_0-9A-Za-z])hoge(?![_0-9A-Za-z])」のように書かざるをえません。

他にも、ふだん正規表現を使っていて、HmJre でも「\b」や「\d」や「\s」が
使えたらいいなーと思うことがしばしばあります。

しかし「\w」の仕様との整合性とか考えるとどうすりゃいいのかわからなくなって
なかなか要望を出すには至りません。

--- 以上雑談 ---

[ ]
RE:01709 正規表現置換を行う関数No.01783
IKKI さん 09/05/03 20:04
 
こんにちは。IKKI です。

今更ながら ReplaceReguar() を使ってみて問題に気づきました。

●テストマクロ
// 文字列中の「\」をすべて「\\」に置換したい
$self = "C:\\hoge\\fuga\\piyo\\uguu.txt";
$search = "\\\\";
$replace = "\\\\\\\\";
$result = dllfuncstr("ReplaceRegular", $search, $self, 0, $replace);
message $result;

●期待した結果
C:\\hoge\\fuga\\piyo\\uguu.txt

●実際の結果
C:hoge\fuga\piyo\uguu.txt

おそらく 2 つの問題があります:

 (1) 置換文字列中の「\」の扱いがおかしい
 (2) 最初にヒットした 1 か所しか置換されない

(2)に関しては私が言葉足らずだったかもしれません。
当初要望の意図は、対象文字列中に出現する検索文字列を全置換したい
ということでした。

全置換ができないと、上述したメタ文字エスケープのような頻出する処理を
簡単に書くことができず、せっかく追加していただいた関数の利用価値が
半減してしまいます。

# というか、最初の 1 個だけ置換する関数があっても実際には使いどころが
# ないような気が…?
# 「どうしても最初の hoge だけを fuga に置換したい」という場合も
# 下記のようにすれば全置換で対応可能かと思います。
# dllfuncstr("ReplaceRegular", "^(.*?)hoge", $self, 0, "\\1fuga");

というわけで、文字列変数に対して全置換を行う関数が欲しいところです。
ご返答は連休明けで結構ですので、ご検討のほどよろしくお願いいたします。


秀丸エディタ v7.11 + HmJre v2.00
Vista SP1

[ ]
RE:01783 正規表現置換を行う関数No.01784
秀まるお さん 09/05/06 11:33
 
>  (1) 置換文字列中の「\」の扱いがおかしい

 調べてみたら、たしかに「\\」の扱いがバグってました。さっそく修正させて
いただきます。

>  (2) 最初にヒットした 1 か所しか置換されない

 これについては第5パラメータを追加するってことで対応したいと思います。

 第5パラメータを省略するか、または0を指定した場合は1つの置換のみ、1
を指定した場合は全置換、という動作にします。

[ ]
RE:01784 正規表現置換を行う関数No.01785
IKKI さん 09/05/06 13:32
 
こんにちは。IKKI です。
休日にご対応いただき恐縮です。

>  第5パラメータを省略するか、または0を指定した場合は1つの置換のみ、1
> を指定した場合は全置換、という動作にします。

これについては

 ・第 5 パラメータは置換を行う最大回数を指定
 ・-1 が指定された場合は全置換

とするのが良いかと思います。
PHP の preg_replace 関数や 田楽 DLL の GSUB 関数とも整合性がとれます。

[ ]
RE:01784 正規表現置換を行う関数No.01790
h-tom さん 09/05/07 06:11
 

h-tom です。
一応関連する話題なので、こちらに報告しておきます。

> これについては第5パラメータを追加するってことで対応したいと思います。
>
> 第5パラメータを省略するか、または0を指定した場合は1つの置換のみ、1
>を指定した場合は全置換、という動作にします。
hmjreのヘルプで、ReplaceRegular, ReplaceRegularNoCaseSense関数の説明ですが、
第4パラメータのところが、整数型になってます。

誤:第4パラメータ(数値型):
正:第4パラメータ(文字列型):

[ ]
RE:01790 正規表現置換を行う関数No.01793
秀まるお さん 09/05/07 09:30
 
 毎度ご指摘ありがとうごさいます。

 実はこの前こっそり直した所でした。

[ ]
RE:01785 正規表現置換を行う関数No.01794
秀まるお さん 09/05/07 09:33
 
>  ・第 5 パラメータは置換を行う最大回数を指定
>  ・-1 が指定された場合は全置換

 パラメータが省略された場合は「0」が指定されたのと同じになるので、これ
だとちょっと都合が悪い気がしますけど。

 しいてやるなら「0または負の数」で全置換という仕様にするとか。

[ ]
RE:01794 正規表現置換を行う関数No.01795
秀まるお さん 09/05/07 11:08
 
 やっぱり第5パラメータは「全置換するか1つだけ置換か」ってフラグの指定
にしてアップロードします。

[ ]
RE:01795 正規表現置換を行う関数No.01796
IKKI さん 09/05/07 12:24
 
こんにちは。IKKI です。

>  やっぱり第5パラメータは「全置換するか1つだけ置換か」ってフラグの指定
> にしてアップロードします。

了解しました。よろしくお願いいたします。

[ ]