2010-03-17 38 views
5

Tôi đang tìm kiếm một giải pháp cho việc tách một chuỗi có chứa văn bản theo định dạng sau:Làm cách nào để tách chuỗi bằng khoảng trắng trừ khi bên trong một chuỗi được trích dẫn?

"abcd efgh 'ijklm no pqrs' tuv" 

mà sẽ tạo ra kết quả như sau:

['abcd', 'efgh', 'ijklm no pqrs', 'tuv'] 

Nói cách khác, nó chia tách bởi khoảng trắng trừ bên trong một chuỗi trích dẫn duy nhất. Tôi nghĩ rằng nó có thể được thực hiện với NET regexps bằng cách sử dụng "Lookaround" nhà khai thác, đặc biệt là cân bằng các nhà khai thác. Tôi không chắc về Perl.

Trả lời

15

Sử dụng Text::ParseWords:

#!/usr/bin/perl 

use strict; use warnings; 
use Text::ParseWords; 

my @words = parse_line('\s+', 0, "abcd efgh 'ijklm no pqrs' tuv"); 

use Data::Dumper; 
print Dumper \@words; 

Output:

C:\Temp> ff 
$VAR1 = [ 
      'abcd', 
      'efgh', 
      'ijklm no pqrs', 
      'tuv' 
     ];

Bạn có thể nhìn vào mã nguồn cho Text::ParseWords::parse_line để xem các mô hình sử dụng.

+1

Tôi thích cách "làm cách nào để thực hiện việc này?" câu hỏi mà tôi từng có về Perl đã được trả lời nhanh chóng bằng cách "Sử dụng mô-đun này thực hiện chính xác những gì bạn muốn". – jergason

+0

Hình có một gói để làm chính xác những gì tôi cần. Tôi không chắc mình đang tìm gì. Bạn là một ngôi sao nhạc rock, cảm ơn! – Kivin

+5

@ Jergason đổ lỗi cho những người tuyệt vời, khi họ * không * tìm chính xác những gì họ cần, và phải tự viết nó, CPAN kết quả sau đó. :) – hobbs

2

Vì vậy, bạn đã quyết định sử dụng regex? Bây giờ bạn có hai vấn đề.

Cho phép tôi suy luận một chút. Bạn muốn có một số trường tùy ý, trong đó một trường bao gồm văn bản mà không chứa khoảng trống, hoặc được phân tách bằng dấu cách và bắt đầu bằng dấu ngoặc kép và kết thúc bằng dấu trích dẫn (có thể với khoảng cách giữa các khoảng trắng).

Nói cách khác, bạn muốn làm những gì mà trình bao dòng lệnh thực hiện. Bạn thực sự chỉ nên sử dụng lại một cái gì đó. Nếu không được, bạn nên nắm bắt một lĩnh vực tại một thời điểm, với một cái gì đó regex như:

^ *([^ ]+|'[^']*')(.*) 

đâu bạn nối thêm nhóm một danh sách của bạn, và tiếp tục vòng lặp với nội dung của nhóm 2.

Một duy nhất vượt qua một regex sẽ không thể nắm bắt được một số lượng lớn các trường. Bạn có thể có thể phân chia trên một regex (python sẽ làm điều này, không chắc chắn về perl), nhưng kể từ khi bạn đang phù hợp với những thứ bên ngoài không gian, tôi không chắc chắn rằng thậm chí là một lựa chọn.

3
use strict; use warnings; 

my $text = "abcd efgh 'ijklm no pqrs' tuv 'xwyz 1234 9999' 'blah'"; 
my @out; 

my @parts = split /'/, $text; 

for (my $i = 1; $i < $#parts; $i += 2) { 
    push @out, split(/\s+/, $parts[$i - 1]), $parts[$i]; 
} 

push @out, $parts[-1]; 

use Data::Dumper; 
print Dumper \@out; 
Các vấn đề liên quan