列ごとに一括置換したいNo.07637
h0t0r1 さん 15/06/30 15:33
 
初めまして、h0t0r1と申します。仕事で急に初めて秀丸を使用することになったので
すがマクロ自体、不慣れで困っています。
下記のことをマクロで行いたいのですがコードをご教示いただけますでしょうか。
特にわからないでいるのが、列の指定の方法です。


やりたいこと:

@100列超×10000行超のCSVファイルのデータに対して、
 指定した列のみ全角スペース1個を半角スペース4個に変換したい
A指定列以外に全角スペースがあっても変換したくない
B指定列は必ずしも連続していない
C全角スペースの数は1項目に1個
 (全角スペース1個の項目と、↓の「家族人数」列のように
  スペースの前に数値がある項目も存在します)
D1行目は見出し行、2行目からが明細行
 (変換対象は2行目から最終行の特定の列です)
E変換対象のCSVファイルは複数存在しますがどれもレイアウトは同じですので
 変換したい列番号も同じです


例:

No.,名前,住所,子供有無,住居,家族人数,車有無,備考
001,はなこ,東京都 ,有,マンション,3人, ,
002,たろう,神奈川県,無,アパート ,0 ,有,
003,よしこ,埼玉県 ,有,戸建   ,4人,無,ペットは犬

変換したい列=「子供有無」「家族人数」「車有無」の3列のみ
(家族人数が「0 」と登録されることはあまりないと思いますが
あくまで例と思っていただければと思います。)

秀丸のバージョンは8.52です。

変換対象のCSVファイルは複数存在し、少しおいてまた作業があるので簡易化・ミス
減のためマクロを作成したいです。

他力本願となってしまい本当に申し訳ございませんがお力をお貸しください。
長文すみませんでした。よろしくお願いいたします。

[ ]
RE:07637 列ごとに一括置換したいNo.07638
IKKI さん 15/06/30 20:49
 
h0t0r1 さん、こんばんは。ユーザーの IKKI と申します。

列の選択は selectcolumn 文でできます。
が、選択した列内だけを置換するスマートな方法が、実は秀丸マクロには存在しませ
ん。

h0t0r1 さんのやりたい作業は、Excel などの表計算ソフトを使えば何も苦労せずに
できます。
たとえば Excel なら、対象列を範囲選択した状態で置換すればできますし、その作
業を VBA で自動化することも可能です。
それでもあえて、どうしても秀丸で行う必要があるのでしょうか?


何が何でも秀丸マクロで、ということでしたら、おそらく次のようなマクロになりま
す。

setcompatiblemode 0x02020F;
loaddll "hmjre.dll";
begingroupundo;
disabledraw;
call ReplaceInColumn 3;
call ReplaceInColumn 5;
call ReplaceInColumn 6;
enabledraw;
endgroupundo;
freedll;
endmacro;

ReplaceInColumn:
 gofiletop;
 searchdown "(?<=^([^,]*,){" + str(##1) + "})[^,]*", regular;
 while (result) {
  $$text1 = gettext(foundtopx, foundtopy, foundendx, foundendy, true);
  $$text2 = dllfuncstr("ReplaceRegular", " ", $$text1, 0, "    ", 2);
  if ($$text1 != $$text2) {
   insert $$text2;
  }
  finddown;
 }
 return;

[ ]
RE:07638 列ごとに一括置換したいNo.07639
h0t0r1 さん 15/07/01 04:18
 
IKKI様、コメントありがとうございます。
Excelで出来るご指摘、私もその通りだと思います。なのですが・・顧客の指定で今
回は秀丸を使用することになりました。恥ずかしながら周りに秀丸ユーザーもいるも
ののCSVモードは使ったことがない人ばかりで、ここで質問させていただいた次第です。

教えていただいたコード、いまは実行環境がないので会社に行ってやってみます!置
換対象列が10列ほどあって、1列ずつ記述するのでは大変と感じていたのでとても参
考になります。投稿後調べた程度なのでコードの意味が詳しくはわかっていないので
すが勉強させていただきます。

実行後、またコメントさせていただきます。ありがとうございました。

[ ]
RE:07638 列ごとに一括置換したいNo.07640
山紫水明 さん 15/07/01 10:31
 
 IKKIさん,横から失礼します。
 サブルーチンの部分は
replaceallfast "(?<=^([^,]*,){" + str(##1) + "}[^,]*?) ", "    ", regular;
ではだめでしょうか。
 ただし,繰り返し指定{n}の n には上限があり(ヘルプには見あたりませんが),
希望されている100列超にも及ぶファイルでは多分無理だろうと思います。

                    山紫水明

[ ]
RE:07640 列ごとに一括置換したいNo.07641
h0t0r1 さん 15/07/01 15:50
 
IKKI様、山紫水明様

コメントありがとうございました。
お二方の方法で試したところ、どちらも問題なく置換できました。

100列超と申し上げたのですが私の勘違いで、今回置換対象のデータは80列程度でし
た(100列超なのは別データでした)。

自分で書けるかというと難しいですが概ねコードの意味もわかってきました。ただ、
"(?<=^([^,]*,){" + str(##1) + "})[^,]*"
の部分が難しく思うのですが、
先に指定した列番号の項目についてカンマ内で何か文字列を前方一致で検索・・して
いるのでしょうか。特に「^」「,」「{}」の意味がよくわからず、教えていただけま
すでしょうか。

本当に初心者で恐縮です。
お手数をおかけして申し訳ございませんが、よろしくお願いいたします。

[ ]
RE:07641 列ごとに一括置換したいNo.07642
h-tom さん 15/07/01 17:09
 

h-tom です。

>"(?<=^([^,]*,){" + str(##1) + "})[^,]*"
>先に指定した列番号の項目についてカンマ内で何か文字列を前方一致で検索・・して
>いるのでしょうか。特に「^」「,」「{}」の意味がよくわからず、教えていただけま
>すでしょうか。

秀丸エディタの正規表現はこのページを見てください。
(秀丸エディタのヘルプと同じです。目次− 検索系コマンド− 正規表現)
http://hidemaruo.mydns.jp:81/helpsite/hidemaru/html/190_CmdSearch_Regular.html

最初の「^」は、先頭(行頭)を表します。

二番目の"[]"内の「^」は、文字クラスの否定なので、
  [^,] = 「,」以外の文字
という意味になります。

「{}」は直前のパターンの繰り返し回数指定です。今回はCSVカラム指定です。
「,」今回は正規表現のメタキャラクターではないので、その文字そのものです。

[ ]
RE:07641 列ごとに一括置換したいNo.07643
colder さん 15/07/01 17:57
 
colderです

もうすでに解決したようですが、今回のように置換が正規表現でない単純な文字列な
ら、以下の変換モジュールを使った方が楽です
http://hide.maruo.co.jp/lib/hmconv/hmflistreplace110.html
HmfListReplace.hmf 変換リストによる置換 V1.1
これを使うと、以下の内容をlist.txtを用意しておくと
 ,    
//list.txtここまで
マクロは以下のようになります
setcompatiblemode 0x10000F;
selectcolumn 3;
reservemultisel;
selectcolumn 5;
reservemultisel;
selectcolumn 6;
reservemultisel;
selectreservedmultisel;
filter "HmfListReplace.hmf" , "ListReplace" , "1010C:list.txt";

[ ]
RE:07642 列ごとに一括置換したいNo.07644
h0t0r1 さん 15/07/02 14:10
 
h-tom 様

コメントありがとうございます。

理解が足りなくてお恥ずかしい限りです。一応用語や記号の意味は調べてはいたので
すが繋がるとわからなくなってしまい、お尋ねしてしまいました。
行頭から行末のどの位置にその列があるか示す必要があるのですね。

ヘルプのURLもありがとうございます。
これを見て勉強します。

[ ]
RE:07643 列ごとに一括置換したいNo.07645
h0t0r1 さん 15/07/02 14:20
 
colder様

コメントありがとうございます。色々な方法があるのですね。。
使ってみましたところ、200行程度のものは本当にすぐ完了したのですが、10000行超
のデータでは実行直後に応答なしとなり、一時間ほど経って一度作業まち、また応答
なし・・となっております(いまその状態です)。何か私が間違えたのでしょうか・・
list.txtのファイルをcドライブ直下に置いたのがよくなかったでしょうか。ちなみ
に、実データでは置換したい列は7列あります。

せっかく教えていただいたのに、このような結果で申し訳ありません。。

[ ]
RE:07645 列ごとに一括置換したいNo.07646
colder さん 15/07/02 20:12
 
>使ってみましたところ、200行程度のものは本当にすぐ完了したのですが、10000行
>超のデータでは実行直後に応答なしとなり、一時間ほど経って一度作業まち、また
>応答なし・・となっております(いまその状態です)。何か私が間違えたのでしょう
>か・・list.txtのファイルをcドライブ直下に置いたのがよくなかったでしょうか。
>ちなみに、実データでは置換したい列は7列あります。
>
>せっかく教えていただいたのに、このような結果で申し訳ありません。。

あら、こちらこそ申し訳ないです。
ちいさなファイルでしか試していませんでした。IKKIさんや山紫水明さんのマクロと
比べて、体感的に100倍ほど遅いですね。
お詫びのついでですが、IKKIさんや山紫水明さんのマクロですと、
下記のような"で囲まれた,付きのデータがあると、うまくいかないです。

No.,名前,住所,子供有無,住居,家族人数,車有無,備考
001,はなこ,東京都 ,"有,無",マンション,3人, ,

これをうまく扱えるようにするには、以下のような長ったらしい正規表現を使う必要
があります。
replaceallfast "(?<=^((\"([^\"]|\"\")*\")?(?!\")[^,]*,){" + str(##1) + "}(?:
\"(?:[^\"]|\"\")*?|[^,]*?))(?: )", "    ", regular;


[ ]
RE:07640 列ごとに一括置換したいNo.07647
IKKI さん 15/07/02 23:34
 
HmJre v4 から前方一致の検索開始位置のバックトラック (?) が行われるようになっ
たことをすっぱり忘れてました。
山紫水明さん、ツッコミありがとうございました。

[ ]
RE:07646 列ごとに一括置換したいNo.07648
秀まるお2 さん 15/07/03 10:31
 
 CSV形式データの1項目にヒットさせるとかは、正規表現で書くと非常に難し
いので…、HmJre.dllの中に、それ用の新しい構文を追加してもいいかなぁと思
ったりはします。

 具体的にどういう構文がいいかはちょっと分からないのですが、例えば

 \&csv&

 とか、

 \_csv_

 とか、何か他と重ならないのを考えたらいいのかなぁと思ったりします。

 他には…

 C言語の文字列定数とかHTMLのタグ、あるいは<tag>〜</tag>まで全体とか、あ
るいは「ひらがな」とか「JIS第1水準漢字」とかもあったらいいのかなぁと思
ったりはします。

 やってたらキリが無いかもしれないですが。

[ ]
RE:07648 列ごとに一括置換したいNo.07649
IKKI さん 15/07/03 11:38
 
秀まるおさん、こんにちは。

> やってたらキリが無いかもしれないですが。
それはキリがないですね。(^^;;
検索範囲を絞り込むのは正規表現DLLの役割ではなく、やはり秀丸エディタ側の機能
とするべきでしょう。
colder さんが教えてくださった「変換リストによる置換」を使う方法が正統なやり
方だと思います。
もし何かやるとしたら、
1. 秀丸側で複数範囲に対する変換モジュールの適用を高速化(並列化)する
2. 標準の変換モジュールに正規表現置換機能(リストを使わない、1対1の)を追加する
という感じでどうでしょう。

[ ]
RE:07649 列ごとに一括置換したいNo.07650
秀丸担当 さん 15/07/03 14:04
 

h0t0r1さんのところで遅いという状態を再現してみようとしたところでは、行数
が多いほど最後のほうの変換が遅くなる傾向がありました。
今後のバージョンで改善したいと思います。


変換モジュールで変換することは、こちらで確認した限りでは1つのカラムであ
れば、1万行では数秒でできて、10万行では数分かかりそうでしたが、時間がか
かっても処理中のダイアログが出て、応答なしにはならないです。
複数選択予約(reservemultisel)で離れたカラムを同時に選択しようとすると、
10万行ではしばらく応答なしになりました。
最後のほうの置換の件ではなく、選択そのものの問題だとしたら、07643番の
colderさんのマクロでは、現状では以下のような感じでカラムごとにしたほうが
いいかもしれません。

setcompatiblemode 0x10000F;
selectcolumn 3;
filter "HmfListReplace.hmf" , "ListReplace" , "1010C:list.txt";
escape;

selectcolumn 5;
filter "HmfListReplace.hmf" , "ListReplace" , "1010C:list.txt";
escape;

selectcolumn 6;
filter "HmfListReplace.hmf" , "ListReplace" , "1010C:list.txt";
escape;


あと、「HmfListReplace.hmf」は32bit版の変換モジュールになっています。
「HmfListReplace.hmf64」が64bit版の変換モジュールになっています。

秀丸エディタが64bit版だとして、変換モジュールが32bit版を使われているとし
たら、64bitと32bitの橋渡しをするオーバーヘッドがあって遅いです。
そうだとしたら、HmfListReplace.hmf64のほうを使うといいと思います。

[ ]
RE:07649 列ごとに一括置換したいNo.07651
秀丸担当 さん 15/07/03 16:57
 

標準の変換モジュールに、通常の置換ダイアログ相当の1対1のものを作るとい
う考えもあると思います。
検索/置換ダイアログの「追加の条件」にカラーマーカーを指定できたらいいと
いう話(turukame.3:08650)もあって、これはV8.54ですぐやる話ではないです
が、いずれやろうと考えています。
もしそれができたら、それで済む話かもしれません。
「追加の条件」で考えつつ、変換モジュールも1つのネタとして参考にさせてい
ただきます。

[ ]
RE:07651 列ごとに一括置換したいNo.07652
colder さん 15/07/06 14:07
 
>標準の変換モジュールに、通常の置換ダイアログ相当の1対1のものを作るとい
>う考えもあると思います。
>検索/置換ダイアログの「追加の条件」にカラーマーカーを指定できたらいいと
>いう話(turukame.3:08650)もあって、これはV8.54ですぐやる話ではないです
>が、いずれやろうと考えています。

正規表現置換ができる変換モジュールがあると便利そうなのでとりあえず試作してみ
ました。
実際に使ってみて、改めて標準に欲しいと思いました。
試作したものでもいいんですが、正規表現にhmjre.dllじゃないので、一瞬、頭の切
換が必要になります。
hmjre.dllを使った変換モジュールを作るのは一般ユーザーにはハードルが高いです。
(特に、Unicode対応が文字コードを非公開の秀丸独自コードに変換する必要があって
無理っぽい)
「追加の条件」にカラーマーカーを指定するのも便利そうなのですが、
検索パターンによってはうまくいかないケースも考えられます。
例(現在の「追加の条件」からの推測)
検索対象("[]"で囲まれた部分がカラーマーカーで指定された部分 実際には"[]"はな
い。)
aaaaa[aaaa]aaaaa
検索文字列 a+

[ ]
RE:07652 列ごとに一括置換したいNo.07653
秀まるお2 さん 15/07/06 15:54
 
 colderさんのおっしゃる通り、HmJre.dllと秀丸エディタの間での、
ユニコード文字の扱いが独自(&非公開)なので、HmJre.dllを使った変換
モジュールはうちの会社でないと作れないと思います。

 ということで、一応、僕の方で、そういう変換モジュールを作る方向でなんと
かしたいと思います。

 とりあえず、colderさんに変換モジュールをアップロードしていただいてるこ
とでもあるので、今すぐってことじゃなくて、将来的にということにさせていた
だきたいと思います。

 (っと言ってる間に秀丸エディタの方で、複数選択した部分のみの置換を作っ
てしまうかもしれませんが・・・)

[ ]
RE:07653 列ごとに一括置換したいNo.07654
IKKI さん 15/07/06 18:48
 
> ということで、一応、僕の方で、そういう変換モジュールを作る方向でなんと
>かしたいと思います。
もしやるとしたら、HmJre.dll を変換モジュールとして呼べるようにするだけでもい
いんじゃないかと思いました。

[ ]
RE:07654 列ごとに一括置換したいNo.07655
秀まるお2 さん 15/07/07 18:05
 
 たしかにHmJre.dllに多少細工するのが一番簡単だと思いますが、変換
モジュールは拡張子がhmfまたは64bit版だとhmf64でないといけないので、その
辺で問題がありそうです。

 まだ作り始めてないですが、基本的には秀丸エディタの置換ダイアログの処理
をそのままコピペして、あとはHmJre.dllのReplaceRegularを呼ぶだけかなぁと
思います。

 まだいじってないですけども。

[ ]