[[20150923102824]] 『改行コードがあればpタグを挿入する・・」に関連ax(γ) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『改行コードがあればpタグを挿入する・・」に関連して』(γ)

本記事は「談話室」相当のものです。お急ぎのかたはスキップ下さい。

[[20150922113921]]?
「改行コードがあればpタグを挿入する、テキストファイルの一括処理プログラム」
の議論に関連して、正規表現がらみの事項について、メモします。

 seiyaさんのきれいなコードが示されました。勉強になります。

 私は、
 >VBScriptの正規表現のReplaceは小回りが余りききませんね。
 と書いたのですが、
 実は以前から他の言語との比較上、こうした点について
 もう少しなんとかならないかと思っておりました。 

 昔、別の掲示板で、こんな記事を書いたことがあります。(2008/11/01 12:29:55)

 ==== 以下引用 ========
 以下余談めいた話で恐縮です。お許しください。 
 (1) 
 過去ログでも一度触れたことがあるのですが、 
 $1に対して、 
  ・この例のように、""の中に書けるようなものだけでなく 
  ・任意の関数が適用できればいいなあ 
 と思うことがあります。 

 つまり、 
 例えば、マッチした文字列をStrCovでカタカナに変換したいなどという場合、 
    Debug.Print .Replace(myStr, StrConv("$1", vbKatakana)) 
 などと書ければいいなあと思うわけです。 
 変換後文字列がその都度変わるので無理なのだとは思いますが、 
 できたら便利だなあという気はします。 

  (2) 
 上記のような問題意識から、RegExpオブジェクトのReplaceメソッドを使わずに、
 Replace関数だけを使ったコードを書いてみました。 
 こうしてやれば、 
 .Replace(myStr, StrConv("$1", vbKatakana)) 的なことも可能です。 

 Sub Test2() 
     Dim myStr As String 
     Dim Matches, m 
     Dim matchStr As String, replaceStr As String 
     Dim k As Long, i As Long 

     myStr = "ちゆうおうく" 
     With CreateObject("VBScript.RegExp") 
        .Pattern = "([あ-お])" 
        .Global = True 
        Set Matches = .Execute(myStr) 

        For k = Matches.Count - 1 To 0 Step -1 
           Set m = Matches.Item(k) 
           matchStr = m.Value 
           i = m.FirstIndex 

           replaceStr = myFun(matchStr)'任意の文字列変換 

           myStr = Left(myStr, i) _ 
                & Replace(myStr, matchStr, replaceStr, i + 1, 1) 
        Next 
        Debug.Print myStr 
     End With 
  End Sub 

  Function myFun(s As String) As String 
     myFun = "★" & s 
     'myFun = StrConv(s, vbKatakana) 'こんなことも可能 
  End Function 

 ただ、文字列の連結を多用していますので、文字列が長いときは特にスピードは遅くなると思いますし、スマートでないコードであることは否定できません。 
 ==== 引用終わり ========
 スマートでないは、少し言い過ぎかもしれませんが。

 --------------------------------------------------
 ついでにコメントさせていただくと、
 seiyaさんのコードは、.Executeを繰り返し実行しているわけですが、
 例えば、以下のように書くと、.Executeは一回で済むかも知れません。

    Set matches = .Execute(txt)
    For i = matches.Count - 1 To 0 Step -1
        Set m = matches(i)
        temp = "<p class=""num" & Len(m.submatches(2)) / Len(m.submatches(1)) + 1 & """>"
        k = m.FirstIndex
        txt = Left(txt, k) & Replace(txt, m.submatches(0), temp & m.submatches(0) & "</p>", k + 1, 1)
    Next
  ただ、こちらは文字列連結のコストがかかることがデメリットですが、
  たぶんこちらのほうが早いかも知れません。

< 使用 Excel:Excel2010、使用 OS:Windows7 >


 またまた勉強になります。
 ありがとうございます。

 >>などと書ければいいなあと思うわけです。 

 ですよね。こういう使い方ができれば、くだんのトピでも Len($1) なんてかけば一発変換も可能ですもんね。

 文字列連結のコストについては、私の場合、気にしすぎるくらい気になりますので、もっぱら1次元配列におさめて
 最後に、Join していますが、そういう方法で、負荷圧縮はできるかもしれませんね。

 seiyaさんの、.Execute の件は、拝見して、私も同じように思いました。
 それとは別に、seiyaさんが、よく使われるコード運びで、 Test --> Exucute があります。
 私の場合は、Exucete をかけて、Countを判定するという記述をしておりまして
 最初は、これって2回処理をしているんじゃ? と思ったんですが、手元のいくつかのデータで検証しますと
 なぜか(?)Test を掛けてふるい落としたほうが効率がいいという結果です。
 よし、これからは、seiyaさんのマネをしようと、そう思っています。(でも、クセってなかなか抜けきらず、今でも Exucute 一本コードが多いですが)

 いずれにしても seiyaさんの、できるだけコンパクトなコードに仕立て上げるテクニック、γさんの無謬のコード構成、
 いつかはβも、その域に近づきたいなとは思いますが、はるか遠い道のりです。

 以下は余談です。

 ・今回の、このトピ、某掲示板でいえば給湯室的なものですね。
  ここ、学校では、この種類のトピのタイトルとして、皆さん、先頭に 【談】、(談)、「談」とつけられることが多いようです。
 ・「正規表現」という言葉、さすがに、最近は違和感がなくなりましたが、最初、その存在を知らない時に
  皆さんが、正規表現、正規表現と、見たこともないコードをアップされるのを横目で見て、ひがみ根性まるだして
  「正規表現」って言葉がおかしい! じゃぁ、そうじゃないものを使った分析は「違法表現」「もぐり表現」なのか!
  そうコメントしたこともありました。
 ・「正規表現」は慣れましたが(もちろん、言葉として です。いつかは使うほうでも慣れたいのですが)
  いまだに慣れないのは「連想配列」ですね。この言葉自体も見かけることが少なくなりましたが、時折目にすると
  何を連想するのかな? と疑問です。ワイルドカード比較用のエンジンでもないですし。

(β) 2015/09/23(水) 13:19


 元スレで<br/>を含めたコードはすぐにできたけど、質問者の意図がいま一つわからなかったので...

 まず私の提示したコードがうまく動いたことを確認したうえで、個々のファイルが大きすぎて「遅くて使い物にならない」
 ということであれば、その時点でメモリ管理(文字列連結)を含めたコードをアップするつもりです。

 確かに正規表現のReplace method は融通が利かないというか、歯がゆく感じます。
 しかし私にとってVBAでの正規表現は「コードが短くて済む」、位にしか考えていないので、あまり期待していません。

 VBAの質問をするとよく「丸投げ」という言葉をよく見ますが、
 私にしてみれば、難解な関数も同様に「丸投げ」と思っています。

 「丸投げ」結構!
 ただし、それなりの返信があれば...
(seiya) 2015/09/23(水) 14:06

 >>私にしてみれば、難解な関数も同様に「丸投げ」と思っています。

 同感です。

 逆に、質問者さんのほうで、VBAはよくわからない。教えてもらっても応用が利かないので関数で教えてほしいと
 そういう質問が少なくないですね。

 で、専門家さんから、火星語(?)のような呪文のような式がさらっと提示される。
 回答者さんからは、「ありがとうございました。できました!」

 こんな難解なものをこれから「応用」できるなら、そもそも質問なんかしなくてもよかったんじゃ?

 なんて、これは関数素人のひがみかもしれませんが、そう思ったりしますね。
 (事実、よくあるのは、A列のデータを対象にしていましたが、レイアウトがかわってB列になりました。どうすればいいですか なんて追加質問があがったり)

(β) 2015/09/23(水) 14:25


 ご指摘のとおり、(談話室)ですな、こりゃあ。
 なかなかインパクトのある冒頭の修正になったでしょ? ww

 ああ、そうそう。<br />を間違って</br>と書いてしまったんだが、
 質問者さんは無視のようだから、問題はないかと。

 seiyaさんのおっしゃることはよくわかります。
 少々の工夫をしたって、それにかける時間と、実行時間を比べてどうなんだと。
 いわゆる"富豪的プログラミング"でいいんですよね、たいていは。同感です。

 ■
 ところで、こちらの掲示板は、一般機能、関数、VBAなどの区分が無い
 ので(それは結構なんです)、おかげで色々な質問を拝見します。

 不思議に思うのは、
 ・関数が一番簡単で、
 ・メニューを使ったソートだとか、フィルタが次に難しくて、
 ・マクロは何でも難しい
 と思っている方が時々います。
 関数以外はわからないので関数でないと困ると、
 パズル的なものまで是非関数でとおっしゃる。
 これがわからない。
 場合によっては、関数が一番難しいことがある。

 ■
 とある本の冒頭に、幼いアインシュタインが叔父さんに「代数学って何?」と
 尋ねたのに対して、頭のよい叔父さんは「ずるい算術だよ」と答えたという話が
 でてくる。
 幼いころ難しいことの代名詞として「鶴亀算」があるが、長じて連立方程式を学ぶと、
 それらがいとも機械的に解けてしまうわけだ。

 それと同じで、簡単なマクロを使ったり、備わった機能を適当に組み合わせて
 いくことが重要で、なんでも関数と、余り長考しない方がよい。
 少し別の角度、方法で考えると、むしろ素直に対応できたりすることが多い。

 ■
 さらに別の話で恐縮だが、コードを何でもかんでも示してしまうのは、
 小学三年生が乗っている自転車に、あえて補助輪を付けてしまうようなものではないかと
 思うことがある。
 ある程度、自分で推進する力があれば、惰性で自転車は進むものだ。
 自転車が進めば、バランスを取る能力も高まり、もっとうまく乗り回せる。

 別の掲示板であるが、来る人来る人の自転車に、補助輪を片っ端から付けてしまう、
 自転車屋 主人のようなかたがいて、どうなんだろうかな、と思うことがある。
 需要があるから供給があるのか知らないが、補助輪をとってあげて、自分で推進する力を
 つけてもらうことも、時には必要ではないかと思う次第である。

(γ) 2015/09/23(水) 18:43


 余談の余談です。

 > 実は以前から他の言語との比較上、こうした点について
 > もう少しなんとかならないかと思っておりました。

 じゃあ、他の言語ではどんな芸当ができるのか、と問われれば、
 (問われたと させてください。そうしないと話が続かない)
 例えば、Rubyなんかでは、こういう風に書ける(ご存じの方も多いと思うが)。

     Dir::glob('D:/MyDocuments/201509/test1/*.txt').each do |f|
         buf = open(f,"r"){|file| file.read } 
         file2 = f.sub("/test1/","/test2/") 
         open(file2,"w"){|g|
             buf.gsub!(/([^\n]+)(\n)(\2*)/){|match|
                 ptag = '<p class="num' + (1 + $3.size).to_s  + '">'
                 ptag + $1 + "</p>" + "\n" + $3     
             }
             g.print buf
         }
     end 

 String#gsub!メソッドは、それぞれのマッチごとに、
 マッチ文字列が ブロック変数(上記のmatchという変数)に渡されるのみならず、
 部分マッチ文字列が自動的に$1,$2・・・などにセットされる。

 これを{から}までのいわゆる"ブロック"の中で処理し、
 最後の処理で返される文字列を使って、
 元の文字列のマッチ文字列(VBScriptで言えば、matches(i).Valueに相当する部分)を
 置き換える ことができる。
 その際、$1,$2・・・は、""のなかではなく、通常の変数として用いることができる。

 (ちなみに、Windows上でRubyを使用する場合、テキストモードでファイルを読み込むと、
 自動的に \r\n → \n が行われ、
 一方、書き込む際には、
 自動的に \n → \r\n が行われるので、
 作業自体は\n を使うだけでよいわけである。
 むろん、バイナリモードで読み書きすれば、こうした自動変換は行われない。
 この場合は、\r\nを相手にしないといけないし、
 逆に、改行コードの判定をするならバイナリモードで読み込む必要があるわけだ。)

(γ) 2015/09/23(水) 22:46


 正規表現の後発組で、かつ他言語の経験もないβは、見よう見まねでVBScriptのエンジンを使いながら
 たとえば、そのメタ文字って何があるのかと、そこから手探り。
 書籍を購入しても、VBScriptはこうだよと、まとまって説明しているものに出会わず、いろんなサイトで
 説明しているものを拾い集めて、あるいは回答されるコードのパターンを、せっせとメモにため込んで
 リファレンスにしていました。

 最近、ようやく、(今までの捜し方がわるかったわけですが)

https://msdn.microsoft.com/ja-jp/library/cc392020.aspx

 こんなページをゲット。
 13のセクションがあるようなので、1セクション、1週間で読んだとして、3〜4か月後、来年早々には
 少しわかるようになるかも・・なぞと、とらぬ狸の皮算用をしております。

(β) 2015/09/23(水) 23:22


 オンラインでも良いですが、ローカルにchm形式のヘルプファイルを
 持っておかれると何かと便利かと思います。
 内容はたぶん同じかと思いますが。

 (1)
https://www.microsoft.com/ja-jp/download/details.aspx?id=1406
 のダウンロードをクリックし、
 自己解凍形式の
 scd56jp.exe
 をダウンロードします。

 (2)
 それを実行(自己解凍)して得られるヘルプファイル 
 Script56.CHM 
 が有用かと思います。

 (上記は、今私がやってみましたので、問題なく実行できるはずです)

 VBScriptのところに、「正規表現の概要」がありますし、
 関連するオブジェクトの リファレンスもあります。

 なお、時々、JScriptを使うときにも重宝するヘルプファイルです。

(γ) 2015/09/23(水) 23:41


 ありがとうございます

 さっそくダウンロードしました。
 やはり、ローカルのほうがいいですねぇ。

(β) 2015/09/24(木) 00:20


 少しでもお役に立てたのなら幸甚です。ご丁寧にどうも。
 3〜4か月後、というより、もうすでに十分ご存じの事ばかりと拝察いたします。

 さて、くだんのHTML化の件ですが、私には見栄えの改行の高さのことしか頭になく、
 "段落"ということのとらえ方が違うとしか思えません。
 段落というものはあくまで空行と空行ではさまれた部分と考えるのが一般的でしょう。

 一行一行を<p class="num1"></p>で区切ってしまうと、例えば、
 <span style="color : red">が複数行にわたって適用されているとすると、
 それをぶち切ってしまい、最初の改行以降は赤字が無効になると思う。
 まあ、所詮は他人のことなんで、朝からこんなことを書いているほうが、よほど どうかしているが。

 おつきあいいただいた皆様ありがとうございました。

(γ) 2015/09/24(木) 07:03


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.