2008年09月28日

PowerShell を学ぶわけと正規表現

なぜ PowerShell を学ぼうとしたのかという理由を書いていませんでしたね。

理由はこうです。


1.ウェブページ作成の実習がありました
2.とは言っても今回はほとんどHTMLのひな形に文章を入れていくだけ
3.評価の基準としては、HTML的にどうこうよりも中身の「量」。もちろんHTMLとしての正しさはチェックしますがそれは別な話で。
4.サーバ上の生徒フォルダにある「index.html」のファイルサイズを比べてみた
5.するときちんとHTMLを理解して、ひな型の不要な部分をバッサリ削除している生徒は中身があるのにファイルサイズは小さくなりこれでは評価できない
6.そこでテキスト部分だけを一気に取り出して、ユーザ名ごとに文字数またはバイト数を並べたい(ブラウザに表示して文書を全選択してエディタで保存し直すイメージ)
7.つまり、生徒フォルダ毎の index.html の中から正規表現を使ってタグを取り除いた純粋なテキスト部分のサイズを比べたい
8.それを何らかのスクリプト言語を使って一括でいけないか

ということ。ただし成績はもう付けてしまったのでウェブページ関係の評価は後期の成績に廻すことになりました。

Excel VBA などでもできると思いますが、オブジェクト指向なスマートさはなさそうなので、WSH か PowerShell かなぁということで。Perl や Ruby でもできそうですけど。

これを書き始めてから実は仲間のブログでツールを組み合わせて同じことをやっている方がいました。

ネットで教科「情報」日記 : Web本文の文字数をカウントする

早く気がついていれば……。まぁ勉強し始めたのですから、ちょっと追求してみます。

そういうわけで、HTMLファイルからタグを取り除く正規表現が必要です。今回は外側から(再帰的に生徒フォルダを探し index.html を取り出す操作)よりも内側から(正規表現を使って HTML ファイルからタグを取り除く方)を優先してみました。

正規表現に関してはまともにかっちりとやったわけではないのですらすらとはでてきません。Google 先生が頼りです。

いろいろ調べてみました。

【注意】この記事を書くに当たってエスケープするのがメンドウでしたので「<」や「>」はすべて全角で表現しています。リストを試す場合は半角に置き換えてください。また、「PS >」となっているのは、PowerShell 上で入力したコマンドであることを示している。「PS >」自体は入力してはいけない。

HTMLタグを取り除く - にししの Perl-CGI Tips ふぁくとりー


によると、

HTMLタグは、「 < 」で始まって「 > 」で終わります。この間の文字列をすべて削除すれば良いわけですね。
$source =~ s/<.*?>//g;


と書いてあります。「=~」がパターン結合演算子だったりするのですが Perl での表現ですよね。使えなさそう。試しにやってみる。

用語 '~' は、コマンドレット、関数、操作可能なプログラム、またはスクリプト ファイルとして認識されません。」だそうで。やっぱりだめだ。これを PowerShell でどう表現するのかを追っかけるより他を当たろう。

Windows PowerShell 正規表現を記述する

はさすがマイクロソフト。ずいぶん参考になりました。でもここに書かれているのは「マッチするかどうか」でTrue や False を返す方法ばかりです。マッチしなかった文字列を取り出したいので却下。

正規表現を使って文字列から部分文字列を取り除くには?[C#、VB] − @IT

タイトルからしてお分かりの通り、PowerShell に関する記事ではありません。C# や VB での話。試しに、テキストエディタでソースを保存し、「Visual Studio 2005 コマンド プロンプト」からコンパイルすると実行ファイルができあがる。これを実行するとソースの中にある「http://www.atmarkit.co.jp/」に対してタグを取り除いた結果が表示される。が、ここでのやりたいこととちょっと違う感じです。という訳で却下。ただし regex クラスというのが正規表現の操作に関係ありそうなことがわかりました。調べてみると regex というのは「regular expressions」のこと。訳すと「正規表現」という意味だそうです。なるほど。

比較演算子(PowerShell 入門)

もなかなか参考になりました。

文字列 (Windows PowerShell) - ++c++; // 未確認飛行 c

にたどり着いてようやく文字列(Sring オブジェクト)に対して演算子を作用させる(「メッセージを送る」と言うことでしょうか)ことでいろいろ取り出せることが判りました。

例が載っています。

PowerShell では単純に変数だけ書いて Enter を押すと中身が表示される訳ですが、

PS > $a = "Windows の新しいコマンドライン シェルです。"
PS > $a
Windows の新しいコマンドライン シェルです。


この2行目を変えます。

PS > $a = "Windows の新しいコマンドライン シェルです。"
PS > $a -replace "です。", "なのですよ。"
Windows の新しいコマンドライン シェルなのですよ。


最初に変数「$a」に文字列を代入。
次の行で「$a」に対し、「-replace」という演算子を作用させています。その後に「置換したい部分」,「置換後の文字列」が続きます。そしてこの「-replace」は正規表現にも対応しています。

ということは、「<.*?>」を空文字に置き換えれば良さそうです。

PS > $a = "<html><body>aaaa</body></html>"
PS > $a
<html><body>aaaa</body></html>
PS > $a -replace "<.*?>",""
aaaa


できました!できてみるとえらく簡単ですねぇ。

ヒアドキュメントの書き方もありました。「@"」で始めて「"@」で終わるか、「@'」で始めて「'@」で終わるということです。違いは変数を展開するかどうかということですが取りあえず後回し。

PS > $a = @'
>> <html>
>> <body>
>> <p>aaaa</p>
>> </body>
>> </html>
>> '@
>>


こうすることで、$a に改行も含んだ複数行の文字列を代入できます。これに先ほどの正規表現の置換を当てはめると、うまくいきました!
PS > $a -replace "<.*?>",""


aaaa



regex結果02

キレイにタグが無くなっています!
出力結果を別な変数に代入してみます。

PS > $b = $a -replace "<.*?>",""



そして、$b は単なる文字列ではなく、PowerShell においては、String オブジェクトになっています。とすれば文字数は「.length」プロパティを見ればいいはず。

PS > $b.length
8

regex結果03

おーできた。目的達成したぁ。

$b として代入する前の状態からオブジェクトのはずだとすれば、いきなり評価できるのかな?

PS > ($a -replace "<.*?>","").length
8

regex結果04

んーすごい。さすがオブジェクト指向。良い感じです。
posted by n_shimizu at 18:41| Comment(2) | TrackBack(1) | PowerShell
この記事へのコメント
<.*?>は<[^<]+?>と書かないと危ないのでは?
Posted by あれま at 2011年03月06日 18:55
>あれまさん

そういえば、なんで最初と最後の「<」と「>」に引っかかってすべて消える……とならないのでしょうね。あ、それは「?」で最小一致になるのか。あとは「<>」の中に「<>」があるような入れ子の心配でしょうか。なるほど。

ありがとうございます。
Posted by n_shimizu at 2011年03月07日 19:23
コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/20175902
※言及リンクのないトラックバックは受信されません。

この記事へのトラックバック

エクセル vba
Excerpt: エクセル vbaについての情報です。
Weblog: エクセル vba
Tracked: 2008-12-26 22:27