tr///による置換(第8章「もっと正規表現」続き)

英語の大文字と小文字を入れ替えたい場合に以下のようにしてもダメだ。

my $str = "How I wonder what you are.\n";
$str =~ s/[A-Z]/lc($&)/ge;
$str =~ s/[a-z]/uc($&)/ge;
print $str;

http://ideone.com/IJRrI
すべて大文字になってしまう。
そこで、tr///なるものを使いましょう、と。

my $str = "How I wonder what you are.\n";
$str =~ tr/A-Za-z/a-zA-Z/;
print $str;

http://ideone.com/l1nsG

tr/置換元の文字リスト/置換先の文字リスト/オプション

これを使うと、置換元の文字リストから置換先の文字リストへの変換が行われます。

ということだけど、

  • なんでA-Zをa-zに、a-zをA-Zに交換すると分かるのだろう?
    • さらに、なんでaをAに、Hをhに変換すると分かるのだろう?
  • 今までは文字クラスを表す時は[A-Za-z]みたいにbracketで囲んでたよね?
  • tr/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/ってやってもいいのかな?
  • 「文字リスト」って何だろう?そんな用語は今まで出てない気がするんだけどなぁ...。

簡単な暗号

my $str = "How I wonder what you are.\n";
$str =~ tr/a-mn-zA-MN-Z/n-za-mN-ZA-M/;
print $str;
$str =~ tr/a-mn-zA-MN-Z/n-za-mN-ZA-M/;
print $str;

http://ideone.com/CIE4k

tr///のオプション

オプション 意味
/c 置換元の文字セットを反転させる(complement)
/d 置換元にあるが、置換先に対応する文字がなければ削除する(delete)
/s 置換した文字が連続したら1つにまとめる(squash)
/U UTF-8として扱う
/C 8ビット文字(octet)として扱う

s///のときとは意味が違うのね。...ってか、s///のときは「修飾子」って呼んでたのに、なぜtr///のときは「オプション」なんだろ?

tr///の慣用句

英大文字の数を数える
my $str = "This is Perl.";
my $count = ($str =~ tr/A-Z/A-Z/);
print $count, "\n";

http://ideone.com/tRk2h
tr///の戻り値は置換した文字数らしい。

$nameを$unameに代入し、$unameの方だけをすべて大文字にする
my $name = "Yagiey";
(my $uname = $name) =~ tr/a-z/A-Z/;
print "\$name = $name\n";
print "\$uname = $uname\n";

http://ideone.com/RmrW1
つまり、=演算子の戻り値は左辺ということですかね。

英小文字の数を削除する
my $str = 'Yahoo!JAPAN & Yahoo! (USA)';
$str =~ tr/a-z//d;
print "|$str|\n";

http://ideone.com/IFPs5
オプション/dを使わないと消えないのかー。http://ideone.com/uFSz9

英数字以外を1個のスペースに置換する
my $str = 'Yahoo!JAPAN & Yahoo! (USA)';
$str =~ tr/A-Za-z0-9/ /cs;
print "|$str|\n";

http://ideone.com/Mg9GE
/cで置換元の文字セットを「反転」させるというのは「〜でなかったら」になるわけね。

tr/A-Za-z0-9/   /cs

みたいに、置換先がスペース3個じゃなくても大丈夫なんだな。
ちなみに、オプションのsをつけないとスペースが連続する。http://ideone.com/FFdxE