Groovyで文字列の中に半角英数記号以外の文字があるかを検出する正規表現パターンマッチング(修正・改良版)
if (text =~ /[^ -~]+/) { println "半角英数記号以外が含まれている" } else { println "半角英数記号のみ" }
否定条件でもやってみようとしたけど、思うような結果になるパターンが見付からないので割愛。
正規表現パターンマッチングのPerlとGroovyでの書き方の違い(2010-5-20の修正・補足版)
キーワードが含まれているかを判定
Perl(=~を使った場合)
my $text = "apple banana cherry"; print ($text =~ /banana/ ? "yes\n" : "no\n");
Perl(!~と!/.../を使った二重否定)
my $text = "apple banana cherry"; print ($text !~ !/banana/ ? "yes\n" : "no\n");
Groovy(=~を使った場合)
def text = "apple banana cherry" println (text =~ /banana/ ? "yes" : "no")
Groovy(==~を使った場合)
def text = "apple banana cherry" println (text ==~ /.*banana.*/ ? "yes" : "no")
Groovy(matchesを使った場合)
def text = "apple banana cherry" println (text.matches(/.*banana.*/) ? "yes" : "no")
キーワードが含まれていないかを判定
Perl(!~を使った場合)
my $text = "apple banana cherry"; print ($text !~ /banana/ ? "yes\n" : "no\n");
Perl(=~と!/.../を使った場合)
my $text = "apple banana cherry"; print ($text =~ !/banana/ ? "yes\n" : "no\n");
Groovy(=~と!/.../を使った場合)
def text = "apple banana cherry" println (text =~ !/banana/ ? "yes" : "no")
Groovy(==~と!/.../を使った場合)
def text = "apple banana cherry" println (text ==~ !/.*banana.*/ ? "yes" : "no")
Groovy(matchesの結果を!で否定する場合)
matchesで!/.../を使うとコンパイルエラーになるため、結果を!で反転する。
def text = "apple banana cherry" println (!text.matches(/.*banana.*/) ? "yes" : "no")
Groovyのパターンマッチングに関する記事(2010-05-20)の訂正とお詫び
「正規表現パターンマッチングのPerlとGroovyでの挙動が異なる」に関する補足
2010-05-20の記事へのuehajさんのコメントを読んでいただくと分かると思いますが、以下の方法で正しく動くようです。
def text = 'apple banana cherry' if (text =~ /banana/) { println "YES" } else { println "NO" }
ただし、「!~」は、コンパイルエラーが出て使えないため、Perlと全く同じように書けるわけではないようです。
(text !~ /.../ は、 text ! ~/.../ と解釈され、!演算子が正しくない位置にあると解釈されるため?)
「Groovyで文字列の中に半角英数記号以外の文字があるかを検出する正規表現パターンマッチング」の訂正とお詫び
以下の部分に誤りがありました。
if (text !=~ /.*[ -~]+.*/) { println "半角英数記号以外が含まれている" } else { println "半角英数記号のみ" }
この場合、text != ~/.*[ -~]+.*/ となり、必ず真になるため、マッチングに使えません。
記事に誤りがあった事をお詫びします。
さらに、==~演算子を使うほうのソースも、上で説明している通り、=~演算子を使う方法で書くことができ、その場合、左右の.*は不要となります。(.matchesを使った場合は.*が必要)
Groovyで文字列の中に半角英数記号以外の文字があるかを検出する正規表現パターンマッチング
if (text ==~ /.*[^ -~]+.*/) { println "半角英数記号以外が含まれている" } else { println "半角英数記号のみ" }
マッチング条件を反対にすると、
if (text !=~ /.*[ -~]+.*/) { println "半角英数記号以外が含まれている" } else { println "半角英数記号のみ" }
Javaっぽく書くと、
if (text.matches(/.*[^ -~]+.*/)) { println "半角英数記号以外が含まれている" } else { println "半角英数記号のみ" }
正規表現パターンマッチングのPerlとGroovyでの挙動が異なる
my $text = 'apple banana cherry'; if ($text =~ /banana/) { print "YES\n"; } else { print "NO\n"; }
def text = 'apple banana cherry' if (text ==~ /banana/) { println "YES" } else { println "NO" }
同じ正規表現パターンでも、Perlでは"YES"、Groovyでは"NO"となってしまう。
Groovyでマッチングさせるには、次のようなパターンに変える必要がある。
def text = 'apple banana cherry' if (text ==~ /.*banana.*/) { println "YES" } else { println "NO" }
どうやら前後に空文字を含む任意の文字列があると宣言しなければならないらしいので要注意。(Groovyのバージョンは1.6.8)
PerlでSQL接続/操作を学ぶための自作ドリル
DBI経由でPostgreSQLに接続し、データの登録/参照を行う。
問題
CSVファイルの内容をDBに登録する
DBとテーブルはPgAdmin3で用意する。
CSVファイル(sample.csv)
name,email,address "山田 太郎",taro.yamada@xxx.com,"東京" "田中 次郎",jiro.tanaka@xxx.com,"大阪" "阿部 三郎",saburo.abe@xxx.com,"名古屋"
実行結果
$ insert_sql.pl sample.csv
DB登録内容(テーブル)
name | address | |
---|---|---|
山田 太郎 | taro.yamada@xxx.com | 東京 |
田中 次郎 | jiro.tanaka@xxx.com | 大阪 |
阿部 三郎 | saburo.abe@xxx.com | 名古屋 |
DBの内容をXMLファイルに書き出す
DB登録内容(テーブル)
name | address | |
---|---|---|
山田 太郎 | taro.yamada@xxx.com | 東京 |
田中 次郎 | jiro.tanaka@xxx.com | 大阪 |
阿部 三郎 | saburo.abe@xxx.com | 名古屋 |
実行結果
$ select_sql.pl sample_out.xml
<?xml version="1.0" encoding="UTF-8"?> <addressBook> <person> <name>山田 太郎</name> <email>taro.yamada@xxx.com</email> <address>東京</address> </person> <person> <name>田中 次郎</name> <email>jiro.tanaka@xxx.com</email> <address>大阪</address> </person> <person> <name>阿部 三郎</name> <email>saburo.abe@xxx.com</email> <address>名古屋</address> </person> </addressBook>
XML::TreePPを使ってみる
use strict; use warnings; use utf8; use IO::File; use XML::TreePP; use Data::Dumper; binmode STDIN, ':utf8'; binmode STDOUT, ':utf8'; binmode STDERR, ':utf8'; # Input Check if (@ARGV != 1) { print STDERR "Please input XML file name.\n"; exit 1; } my $xmlin_name = $ARGV[0]; # File Check unless (-f $xmlin_name) { print STDERR "$xmlin_name is not found.\n"; exit 1; } # Input XML my $xml_parser = XML::TreePP->new(utf8_flag => 1, use_ixhash => 1); my $xml = $xml_parser->parsefile($xmlin_name); print Dumper($xml); my $persons = $xml->{'addressBook'}{'person'}; # Output XML Data for (my $cnt = 0; $cnt < @$persons; $cnt++) { print '(' . ($cnt + 1) . ')' . "\n"; foreach my $key (keys %{$persons->[$cnt]}) { print "\t" . $key . ' : ' . $persons->[$cnt]{$key} . "\n"; } } exit 0;
<?xml version="1.0" encoding="UTF-8"?> <addressBook> <person> <name>山田 太郎</name> <email>taro.yamada@xxx.com</email> <address>東京</address> </person> <person> <name>田中 次郎</name> <email>jiro.tanaka@xxx.com</email> <address>大阪</address> </person> <person> <name>阿部 三郎</name> <email>saburo.abe@xxx.com</email> <address>名古屋</address> </person> </addressBook>
実行結果(念のため、読み込んだ直後のデータをDumpする。)
$ perl input_xml_treepp.pl sample.xml $VAR1 = { 'addressBook' => { 'person' => [ { 'name' => "\x{5c71}\x{7530} \x{592a}\x{90ce}", 'email' => 'taro.yamada@xxx.com', 'address' => "\x{6771}\x{4eac}" }, { 'name' => "\x{7530}\x{4e2d} \x{6b21}\x{90ce}", 'email' => 'jiro.tanaka@xxx.com', 'address' => "\x{5927}\x{962a}" }, { 'name' => "\x{963f}\x{90e8} \x{4e09}\x{90ce}", 'email' => 'saburo.abe@xxx.com', 'address' => "\x{540d}\x{53e4}\x{5c4b}" } ] } }; (1) name : 山田 太郎 email : taro.yamada@xxx.com address : 東京 (2) name : 田中 次郎 email : jiro.tanaka@xxx.com address : 大阪 (3) name : 阿部 三郎 email : saburo.abe@xxx.com address : 名古屋 $
このモジュールも、XML::LibXML::Simple同様、マップで取得できるのは便利かも知れない。
でも、異なる名前の要素の順番が、そのままでは保持されないのは同じ。
ただ、use_ixhashオプションを1にする事で、マップの順番が保持されるらしい。(Tie::IxHashモジュールが必要)
さらに、utf8エンコードの文字データを取り込むためには、utf8_flagオプションを1にしておく必要がある。