2008-10-08 37 views
11

Có cách nào để thực hiện điều này trong một dòng không?Có biểu thức chính quy tương thích Perl để cắt khoảng trắng từ cả hai mặt của chuỗi không?

$x =~ s/^\s+//; 
$x =~ s/\s+$//; 

Nói cách khác, xóa tất cả khoảng trắng đầu và cuối khỏi chuỗi.

+2

"cắt" là tên bình thường để loại bỏ whitepsace khỏi cả hai mặt của chuỗi. bạn có thể: $ title = ~ s/remove/trim/ – Kip

+0

Tôi đang xóa thẻ "pcre" vì đó là tên của thư viện regex C (thư viện hỗ trợ chức năng preg của PHP) và rõ ràng không phải là cách nó được sử dụng đây. –

Trả lời

26
$x =~ s/^\s+|\s+$//g; 

hoặc

s/^\s+//, s/\s+$// for $x; 
+0

Tùy chọn 2: Đó là một mẹo hay, nhưng không thực sự trả lời câu hỏi: D – ephemient

+2

Làm thế nào mà không trả lời được câu hỏi? Nó cắt tỉa từ cả hai phía mà không có sự thay đổi độ lệch của hiệu suất của regex đơn. –

+0

s/^ \ s * (. *?) \ S */\ 1 /; phải thử nhiều lựa chọn thay thế hơn một trong hai tùy chọn đó –

4

Ở đây bạn đi: $x =~ s/\A\s*(.*?)\s*\z/$1/;

2

$ x = ~ s/(^ \ s +) | (\ s + $) // g;

+1

đó là cách tôi luôn làm điều đó .. có vẻ như là dễ nhất. – Kip

+0

vâng, và nó nói ý nghĩa của nó - thay thế khoảng trắng bắt đầu HOẶC kết thúc khoảng trắng với không có gì, trên toàn cầu. –

+2

Chụp parens không được sử dụng hoặc cần thiết - nói chung bạn có thể thay thế chúng bằng cách nhóm parens (?: ...), nhưng trong trường hợp này ưu tiên hoạt động độc đáo và bạn có thể loại bỏ các dấu ngoặc đơn hoàn toàn. – ephemient

-2
$x =~ s/^\s*(.*?)\s*$/$1/; 
+0

Sử dụng \ 1 thay vì $ 1 trong chuỗi thay thế không được khuyến khích trong Perl, xem "Cảnh báo trên \ 1 so với $ 1" trong 'perldoc perlre'. – ephemient

+0

Vì các bộ định lượng tham lam, bạn không cần phải nói điều gì đó giống như [^ \ s] sau khi khớp với \ s +. Ngoài ra, thay vì [^ \ s], bạn chỉ có thể nói \ S. Các phiên bản viết hoa là lớp nhân vật bổ sung. :) –

+0

brian: Có, nhưng chỉ khi tôi thực hiện. * Không chấp nhận. – Lev

0
s/^\s*(\S*\S)\s*$/$1/ 
+0

Sử dụng \ 1 thay vì $ 1 trong chuỗi thay thế không được khuyến khích trong Perl, xem "Cảnh báo trên \ 1 so với $ 1" trong 'perldoc perlre'. – ephemient

+0

Bạn nói đúng, tôi sẽ sửa nó. –

+0

Vấn đề ở đây là bạn yêu cầu ít nhất 2 ký tự không khoảng trống trong chuỗi, hoặc nó sẽ không hoạt động. – bart

30

câu hỏi đầu tiên của tôi là ... tại sao? Tôi không thấy bất kỳ giải pháp đơn regexp nào có thể đọc được nhiều hơn regexp mà bạn đã bắt đầu. Và họ chắc chắn không phải ở đâu gần như nhanh.

#!/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*$/ 
       } 
      }, 
     } 
     ); 

cho kết quả trên máy tính của tôi:

 
      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%  -- 

Sửa: runrig là đúng, nhưng để thay đổi chút. Tôi đã cập nhật các mã để sao chép chuỗi trước khi sửa đổi, trong đó, tất nhiên, làm chậm mọi thứ xuống. Tôi cũng tính đến gợi ý của brian d foy trong câu trả lời khác để sử dụng chuỗi dài hơn (mặc dù một triệu người có vẻ như quá mức cần thiết). Tuy nhiên, điều đó cũng gợi ý rằng trước khi bạn chọn kiểu lừa, bạn tìm ra chiều dài chuỗi của bạn như thế nào - những ưu điểm của mẹo được giảm bớt bằng các chuỗi ngắn hơn. Ở tất cả các độ dài tôi đã thử nghiệm, mặc dù, đôi thắng. Và nó vẫn còn dễ dàng hơn trên mắt.

+0

Bạn đang giả định rằng anh ấy đang làm điều này trong Perl, và đó có thể không phải là trường hợp. "Perl-compatible" luôn luôn đặt cờ đỏ cho tôi. –

+0

Đúng - có một chút khó hiểu khi thấy cả thẻ perl và pcre ... – Tanktalus

+0

Tất cả các "kiểm tra" của bạn sẽ thay đổi @x trong lần lặp đầu tiên. Vì vậy, không có ai đang thử nghiệm những gì bạn nghĩ. Bạn cần phải sao chép @x trong người đăng ký của mình. Và trong giải pháp kép, không quấn nó trong vòng lặp for, chỉ cần sử dụng "cho @x". – runrig

5

Tranh luận về giả thuyết, tại sao phải làm như vậy? Tất cả các giải pháp trên là "chính xác" ở chỗ chúng cắt khoảng trắng từ cả hai mặt của chuỗi trong một lần truyền, nhưng không có gì có thể đọc được một cách khủng khiếp (có thể là this one). Trừ khi đối tượng cho mã của bạn bao gồm các lập trình viên Perl cấp chuyên gia, mỗi ứng cử viên trên phải có nhận xét mô tả những gì họ làm (có thể là một ý tưởng hay). Ngược lại, hai dòng này thực hiện được điều tương tự mà không sử dụng lookaheads, kí hiệu, midichlorines hoặc bất cứ điều gì đó không phải là ngay lập tức hiển nhiên đối với một lập trình viên kinh nghiệm trung bình:

$string =~ s/^\s+//; 
$string =~ s/\s+$//; 

Có (cho là) ​​một buổi biểu diễn hit, nhưng như miễn là bạn không quan tâm đến một vài micro giây khi thực thi khả năng đọc được thêm sẽ đáng giá. IMHO.

+0

Hiệu suất đạt được? Ai có thể tranh luận điều đó? Nó nhanh hơn gấp đôi so với bất kỳ giải pháp nào khác được liệt kê. – Tanktalus

+0

Đủ công bằng, tôi đã không chuẩn bị mã vì tôi muốn ra ngoài cửa cho một bữa trưa muộn (rất). Vui mừng khi biết không có hit hiệu suất. – Logan

+0

Chuyên gia Perl? Những người trong khóa học Perl Học tập của tôi sẽ hiểu tất cả các giải pháp này vào cuối ngày thứ hai. –

8

Tanktalus hiển thị điểm chuẩn cho các chuỗi rất nhỏ, nhưng các vấn đề trở nên tồi tệ hơn khi các chuỗi trở nên lớn hơn.Trong mã của mình, tôi đã thay đổi phần trên:

my $a = 'a' x 1_000_000; 

my @x = (
    " $a ", 
    "$a ", 
    $a, 
    " $a" 
); 

tôi nhận được những kết quả này:

  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%  -- 

Như chuỗi lớn hơn, sử dụng "lừa" và "kép" là gần như giống nhau, và giải pháp phổ biến mà hầu hết mọi người đi cho, "duy nhất" (bao gồm cả tôi, bởi vì tôi không thể phá vỡ thói quen đó mặc dù tôi biết điều này), thực sự bắt đầu hút.

Bất cứ khi nào bạn nhìn vào điểm chuẩn, hãy suy nghĩ về những gì nó cho bạn biết. Để xem bạn có hiểu hay không, hãy thay đổi dữ liệu và thử lại. Tạo các mảng dài, vô hướng lớn, v.v. Tạo vòng lặp, greps hoặc regexes tìm nội dung ở đầu, giữa và cuối. Xem liệu kết quả mới có khớp với dự đoán của bạn không. Tìm ra xu hướng là gì. Liệu hiệu suất có tốt hơn và tốt hơn, tiếp cận một giới hạn, đỉnh sau đó bắt đầu giảm, hoặc cái gì khác?

1

Tôi thường làm điều đó như thế này:

($foo) = $foo =~ /^\s*(.*?)\s*$/; 

Tất cả mọi thứ giữa các không gian hàng đầu và các dấu không gian được nhóm và trở về, vì vậy tôi có thể gán nó vào biến cũ.

-1
$var1 =~ s/(^\s*)(.*?)(\s*$)+/$2/; 
Các vấn đề liên quan