めも。


substrを使って、ある一定サイズ(100byte)を超えた文字列を省略するモノを書いた。


substr($str, 100) = ''; # 省略


すると、たまに以下のエラーがでた。

substr outside of string at 〜.pl line 〜


英語が読めないけど、何回かテストしたら、
100byteに達していない文字列に対しては上のようなエラーがでるっぽい。


おそらく、その文字列は100byte以上のメモリを確保してない状態で、
substrで100byte以降を参照しようとしているのが問題なのかな。
ずっと、自動的に最適化してくれるもんだと思ってた。
100って書いても50byteの文字列だったら50byteにあわせるような感じで。


その前に。
良く考えたら、長文を省略した場合にだけ、記号を付加したほうがいいわけで。
よく使われてるのは、…とか、...とかですね。
上の処理で省略記号をつけたら、どんな文字列だろうが最後についてしまうっていう。


なら、あらかじめ、100byte以上なのかどうかを判定すれば、
100byte以降を参照することによるエラーもでないし、
省略符号も100byte以降の文字列と置き換えることで簡単につけられる、と。

if(length($str) > 100){
	substr($str, 100) = '...'; # 省略
}


ちなみに、正規表現の置き換えを使えば、この動作は1行で終わります。

$str =~ s/(.{100}).+/$1.../s;

「.」はワイルドカードですが、デフォルトでは改行にマッチしません。
sオプションをつけることで改行にもマッチするようになります。
そのことを初めて知った時は「何がワイルドカードだよ!」って思いました。
それ以来、僕の中でのワイルドカードは[\w\W]になりました。
また「1行の文字数を制限する」なら後者にsオプションをgオプションにするだけで実現できます。


最近、なんとなく新しいPerlの書き方とかを求めて、海外のフォーラムを良く見ますが、
英文が全く読めなくても、ちょっとした単語(help, please, bestぐらい)が読めて、
スレッドにある各々のソースコードを読むことで、
なんかコレうまくいかないんだけど?とか、こういう書き方がいいよ、って書いてあるのが、
なんとなく、わかるようになってきた。


@おまけ

変数の値の交換。swap。


従来のやり方。(no1)

{
	my $tmp = $s1;
	$s1 = $s2;
	$s2 = $tmp;
}


教えてもらったやりかた。(no2)

($s1, $s2) = ($s2, $s1);


1文ですむじゃん!一時的の変数を作らなくていいじゃん!すばらしい!


べんちまーくをとってみた。

use Benchmark;

timethese (1000,
	{
		no1 => sub {
			my $s1 = 'aaa';
			my $s2 = 'bbbbb';
			
			for (my $i = 0; $i < 10000; $i++) {
				my $tmp = $s1;	$s1 = $s2;	$s2 = $tmp;
			}
		},

		no2 => sub {
			my $s1 = 'aaa';
			my $s2 = 'bbbbb';
			for (my $i = 0; $i < 10000; $i++) {
				($s1, $s2) = ($s2, $s1);
			}
		},
	}
);


けっか

Benchmark: timing 1000 iterations of no1, no2...
       no1:  4 wallclock secs ( 4.03 usr +  0.00 sys =  4.03 CPU) @ 248.08/s (n=1000)
       no2: 10 wallclock secs (10.34 usr +  0.00 sys = 10.34 CPU) @ 96.67/s (n=1000)


後者のほうが2.5倍以上遅くなった!
前者はループ中にいちいち変数宣言しているというのに・・・
$tmpを$s1,$s2と同じところで宣言するようにしたら3倍もの差になったよ。


やはり無名なリストを作る方が手間なんですかね(´・ω・`)