[Ruby Python]正規表現に関しておさらい

正規表現ってかなり頻繁に使うのに、なかなか一発で書けなくて、その度に調べてる気がするので、ここでちょっとまとめてみようと思いました。

個人的に最近よく利用するRubyとPythonでやってみようかな、と思ってます。

pythonに関しては公式で正規表現のサンプルがのったリファレンスがあったのでリンク貼っておきます

http://docs.python.jp/3/howto/regex.html#regex-howto

0.まずはとりあえず使ってみる

[Ruby]

インポートは特別必要ないみたいです。明示的にインスタンスを生成したければRegexp.new(/パターン/)、文字リテラル(1つ目のif文の箇所)でそのままでもOKです。 コンストラクタに与える引数は/(スラッシュ)で囲っても、クォーテーションで囲ってもOKです。

あと、 =~ ってどういう演算子なんだろう・・・と調べてたんですが、これはRegexpクラスのパターンマッチを行うメソッドでした。

ちなみに上記のif文は二つともマッチングします。

[Python]

対してPythonはre モジュールのインポートが必要になります。

re.compile(“パターン”)でインスタンスを生成できます。Pythonのマッチングのチェックには4つのメソッドがあって

・match() 文字列の先頭からマッチするかチェック

・search() 文字列を全体から、どこにマッチするかをチェック

・findall() 文字列内のマッチする箇所全てをリストにして返す

・finditer 文字列内のマッチする箇所全てをイテレータとして返す

上記のサンプルでは”hello”をmatch()でチェックしマッチングしますが、例えば”Bob, hello!”など、文の頭からマッチングしていなければNoneが帰ってきます。findallは後で試しますが、文章中から特定の文字列 のマッチングをしたいときはsearch()のほうがよさそうです。

 

1.特定の文字列パターンにマッチさせる

前項で既に簡単なサンプルを挙げてしまいましたが、もうちょっと使えそうなやつを・・・・。

んー、でも使えるやつってなんでしょ・・・wEメールのマッチングとか、便利なんですけど、ちょっと難易度高いので

・base64に使われている文字列をマッチングさせる

・URL全体からドメイン名をマッチングさせる

の二種類を試します。これRubyとPythonの正規表現、じゃなくて普通に正規表現のはなしになってるかな・・・。まぁよく覚えてないので、そこも含めて復習します・・・。

 

base64に使われている文字は大文字AからZと小文字aからz、数字の1から9、そして記号の+,/,=です。この文字列のみを含むものと、そうでないものをマッチングさせてみます。

[Ruby]

引数に与えた文字列がbase64のものであればマッチングします。(多分間違ってないよね・・・?)

rubyはRailsでの開発で使っただけだったので、コマンドライン引数を取得するところから調べました・・・w

 

[Python]

コマンドライン引数を得るために、sysモジュールをインポートしてあります。

あとはほとんどRubyと同じ。ひとつポイントは

の箇所。パターンの前に小文字のrがありますね。ちゃんとした説明やrをつける理由は一番上に貼ったリンクにありますが、すごく簡単にいうと、正規表現のパターンを宣言するときはrつけると簡単、って感じ。

※公式でも「実行遅いけど、読みやすく簡単だよ!」という触れ込み(笑)

 

次はドメインをマッチングしたいと思います。

下記の条件にマッチングさせてみます

1.http://komaken.me/blog/はマッチングしない

2.http://komaken.meにはマッチングする

[Ruby]

[python]

こんな感じでいいかな・・・・?とりあえず上記の条件はパスできました。

次からは、文章中からURLや任意の文字パターンを抜き出してみたいと思います。

正規表現に関しては比較するとRubyのほうがコード少なくて済みますね。

 

2.文字列パターンにマッチした文字列を抜き出す

[Ruby]

パターンにマッチングした文字列を抜き出すにはStringクラスのscanメソッドを利用します。(それ以外だと$0とかの方法があるみたいですが、簡単で、かつ僕の用途に合ってるのはscanだったので、こちらを選びました。)

マッチングした箇所を抽出することを後方参照と言うらしいのですが、ここでポイントが

http,https,ftpのいずれかをマッチングするためのグルーピングがされていますが、頭に?:がついています。これは後方参照をしない、という意味です。

これをしないと、例えばhttp://www.facebook.comをマッチングさせたときに、後方参照を行うと、http://www.facebook.comとhttpの二つがマッチングしてしまいます。抜き出したいのはhttp://www.facebook.comだけなので、最初のグルーピングには明示的に後方参照が不要だということを定義します。

なので、上記のサンプルはhttp,https,ftpのいずれかで始まり、::/の後に大文字A-Z小文字a-z、そして数字の1-9、ドットが含まれる文字列にマッチングします。

 

[Python]

Pythonではマッチングした文字列を抽出するには、group()メソッドを呼びます。

先ほどのコードを少しいじるだけ+ findall()を使ってみます。マッチした全ての文字列をリストで返すので、使いやすいかなと思います。

変数名もうちょっとマシなのつけたほうが良かったかな・・・。さーせんw

後方参照にマッチさせない書き方はRubyと一緒ですね。よかった。

 

3.文字列パターンにマッチした文字列を置き換える

今度はマッチングした文字列のなかから、特定の箇所を置換えてみます。結局何がしたかったか、というと、渡された文字列からURLを抜き出して、それからhttpとかのプロトコルの部分を消す、ということをしたかったのです。

さっき抜き出したのがhttp://www.facebook.comなので、最終的にはwww.facebook.comという形式にしていきます。

これ、正規表現に詳しい人なら一撃で文字列からwww.facebook.comを抽出することもできるのかもしれませんが、段階を踏んで簡単にできる方法として、http://などを指標にまずは抽出しようと考えました。

置換えにはStringクラスのgsubメソッドを利用します。

コマンドライン引数にファイルパスを指定してやると、その中からドメインを抜き出します。

gsubの使い方はscanと変わりません。第二引数に置換え後の文字列を与えるだけです。今回はhttp://などを消したいので、第二引数は空です。

 

[Python]

置換えのメソッドはsubです。 上記のサンプルではreクラスからsub呼び出していますが、マッチングのためのインスタンスを生成して、インスタンスからsubメソッドを呼び出すこともできます。

プロトコルの部分だけをマッチングさせるインスタンスを別途作成しました。これもうちょっと簡単にする方法あるかな・・・・。

正規表現に関しては個人的にはRubyのほうが直感的で使いやすいかも。

 

基礎的な部分なんだけど、使いたいときにサッと出てこないことが多かったので、以上メモです。入門の入門的な。

 

追記

4.おまけ Python & Ruby リストの重複を排除する

上記の項目3で、指定したファイルからドメインを抽出するスクリプトを書きましたが、重複したドメインが表示されてしまいます。試しにfacebookのトップページからドメインを抽出してみたところ、膨大な重複が検出されました。(当たり前だけど)

そこでそれぞれ重複を排除し、利用されているドメインの一覧を表示するように変更します。

[Rubyにおける重複の排除]

もともとのインスタンス(この場合 変数ms)の状態を残しておきたければ最後の!マークを取って変数に代入すればOKです(破壊的メソッドか、否か)

 

[Pythonにおける重複の排除]

pythonの場合は一件ちょっと複雑ですが、もともとのリスト(変数m)を重複を持たないデータ構造のsetへ変換(set()関数で)

それからlist()関数でlistへ変換。別にset()のままでもいい時はset(m)だけでもいいと思います。

 

これを抽出したドメインのリストに対して処理すれば、すべてユニークになります。

 

[Ruby Python]正規表現に関しておさらい」への1件のフィードバック

  1. ピンバック: Python 正規表現の参考リンク | Pythonでマインドストーム

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です