文字列の両側から空白を削除するPerl互換の正規表現はありますか?
-
06-07-2019 - |
質問
これを1行で行う方法はありますか?
$x =~ s/^\s+//;
$x =~ s/\s+$//;
つまり、文字列から先頭と末尾の空白をすべて削除します。
解決
$x =~ s/^\s+|\s+$//g;
または
s/^\s+//, s/\s+$// for $x;
他のヒント
最初の質問は...なぜですか?単一の正規表現ソリューションが、最初に使用した正規表現よりも読みやすいとは思えません。そして、彼らは確かにそれほど速くない。
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw(:all);
my $a = 'a' x 1_000;
my @x = (
" $a ",
"$a ",
$a,
" $a"
);
cmpthese(-5,
{
single => sub {
for my $s (@x)
{
my $x = $s;
$x =~ s/^\s+|\s+$//g;
}
},
double => sub {
for my $s (@x)
{
my $x = $s;
$x =~ s/^\s+//;
$x =~ s/\s+$//;
}
},
trick => sub {
for my $s (@x)
{
my $x = $s;
s/^\s+//, s/\s+$// for $x;
}
},
capture => sub {
for my $s (@x)
{
my $x = $s;
$x =~ s/\A\s*(.*?)\s*\z/$1/
}
},
kramercap => sub {
for my $s (@x)
{
my $x = $s;
($x) = $x =~ /^\s*(.*?)\s*$/
}
},
}
);
次のマシンで結果を表示します:
Rate single capture kramercap trick double single 2541/s -- -12% -13% -96% -96% capture 2902/s 14% -- -0% -95% -96% kramercap 2911/s 15% 0% -- -95% -96% trick 60381/s 2276% 1981% 1974% -- -7% double 65162/s 2464% 2145% 2138% 8% --
編集:runrigは正しいですが、ほとんど変わりません。変更する前に文字列をコピーするようにコードを更新しましたが、もちろん速度が低下します。また、長い文字列を使用するという別の答えでブライアン・ド・フォイの提案を考慮に入れました(100万は過剰に思えた)。ただし、トリックスタイルを選択する前に、文字列の長さがどのようなものかを把握することもお勧めします。短い文字列を使用すると、トリックの利点が減ります。しかし、私がテストしたすべての長さで、2つの勝ちです。そして、それはまだ目に優しいです。
Tanktalusは非常に小さな文字列のベンチマークを示していますが、文字列が大きくなると問題は悪化します。彼のコードでは、上部を変更しました:
my $a = 'a' x 1_000_000;
my @x = (
" $a ",
"$a ",
$a,
" $a"
);
これらの結果が表示されます:
Rate single capture trick double
single 2.09/s -- -12% -98% -98%
capture 2.37/s 13% -- -98% -98%
trick 96.0/s 4491% 3948% -- -0%
double 96.4/s 4512% 3967% 0% --
" trick"を使用して文字列が大きくなると、および" double"ほぼ同じであり、ほとんどの人が求める一般的なソリューションである「シングル」は(私を含め、私はこれを知っていてもその習慣を破ることができないため)、本当に嫌になり始めます。
ベンチマークを見るときはいつでも、それが何を伝えているかを考えてください。理解できるかどうかを確認するには、データを変更して再試行してください。配列を長くし、スカラーを大きくします。ループ、greps、または正規表現に、開始、中間、終了の要素を見つけさせます。新しい結果が予測と一致するかどうかを確認します。傾向を把握します。パフォーマンスはどんどん良くなり、限界に近づき、ピークに達し、その後低下し始めますか?
おもしろいですね、これを持ってきてください!
最近、 12の(!)異なるトリム実装のパフォーマンスを分析した記事を読みました。
この記事ではJavaScript正規表現の実装を具体的に使用していますが、Perl構文を使用しているため、この議論に適していると思います。
異端者からの議論、なぜそれを行うのですか?上記のソリューションはすべて「正しい」ものです。 1回のパスで文字列の両側の空白を削除しますが、ひどく読みやすいものはありません(これ)。あなたのコードのオーディエンスが専門家レベルのPerlコーダーで構成されていない限り、上記の候補者のそれぞれは彼らが何をするのかを説明するコメントを持つべきです(とにかく良い考えです)。対照的に、これらの2行は、先読み、ワイルドカード、ミディクロリン、または中程度の経験を持つプログラマーにはすぐには分からないものを使用せずに同じことを実現します。
$string =~ s/^\s+//;
$string =~ s/\s+$//;
(おそらく)パフォーマンスヒットはありますが、実行時の数マイクロ秒を気にしない限り、読みやすさはそれだけの価値があります。私見。
ここに行きます: $ x =〜s / \ A \ s *(。*?)\ s * \ z / $ 1 /;
$ x =〜s /(^ \ s +)|(\ s + $)// g;
通常は次のようにします:
($foo) = $foo =~ /^\s*(.*?)\s*$/;
先頭のスペースと末尾のスペースの間のすべてがグループ化されて返されるため、同じ古い変数に割り当てることができます。
またはこれ: s / \ A \ s * | \ s * \ Z // g
s/^\s*(\S*\S)\s*$/$1/
$var1 =~ s/(^\s*)(.*?)(\s*$)+/$2/;
$x =~ s/^\s*(.*?)\s*$/$1/;