2009-06-19 34 views
5

Tôi có một ứng dụng Perl rằng phải mất từ ​​dòng lệnh một đầu vào như:Làm cách nào để mở rộng chuỗi như "1..15,16" vào danh sách các số?

application --fields 1-6,8 

Tôi cần thiết để hiển thị các lĩnh vực theo yêu cầu của người dùng trên dòng lệnh.

Tôi đã nghĩ đến việc thay thế '-' bằng '..' để tôi có thể lưu trữ chúng trong mảng, ví dụ:

$str = "1..15,16" ; 
@arr2 = ($str) ; 
@arr = (1..15,16) ; 
print "@arr\n" ; 
print "@arr2\n" ; 

Vấn đề ở đây là @arr hoạt động tốt (vì nó phải) nhưng trong @ arr2 toàn bộ chuỗi không được mở rộng thành phần tử mảng.

Tôi đã thử sử dụng chuỗi thoát nhưng không may mắn.

Có thể thực hiện theo cách này không?

Trả lời

26

Nếu đây là đầu vào của người dùng, không sử dụng chuỗi eval trên đó nếu bạn có bất kỳ mối lo ngại về bảo mật nào.

Hãy thử sử dụng Number::Range thay vì:

use Number::Range; 

$str = "1..15,16" ; 
@arr2 = Number::Range->new($str)->range; 
print for @arr2; 

Để tránh chết trên một phạm vi không hợp lệ, làm:

eval { @arr2 = Number::Range->new($str)->range; 1 } or your_error_handling 

Ngoài ra còn có Set::IntSpan, trong đó sử dụng - thay vì ..:

use Set::IntSpan; 

$str = "1-15,16"; 
@arr2 = Set::IntSpan->new($str)->elements; 

nhưng yêu cầu phạm vi phải theo thứ tự và không trùng lặp (nó đã được viết để sử dụng trên các tệp .newsrc, nếu có ai nhớ những gì đang có). Nó cũng cho phép các phạm vi vô hạn (nơi chuỗi bắt đầu - số hoặc kết thúc số -), mà phương thức phần tử sẽ được chỉnh sửa.

+4

+1. "Làm đúng" luôn luôn là thích hợp hơn để đánh giá. Nhiều tác dụng phụ ít hơn. – jrockway

+0

Tôi chưa từng gặp số :: Phạm vi trước đó. Tôi đã gửi nó đi để sử dụng trong tương lai. Cảm ơn vì đã làm cho tôi biết về nó! –

+0

Nếu bạn nhập dữ liệu của người dùng, ứng dụng của bạn sẽ tăng lên trên 1..1000000000, trừ khi bạn có khoảng 8GB RAM. Number :: Range-> size() là vô ích ngay bây giờ để ngăn chặn điều này vì nó tạo ra toàn bộ phạm vi để tìm ra kích thước. –

-2

Sử dụng phân chia:

@parts = split(/\,/, $fields); 

print $parts[0]; 
1-6 
print $parts[1]; 
8 

Bạn có thể không chỉ cần đặt một chuỗi chứa '' trong một mảng, và hy vọng nó sẽ chuyển sang yếu tố (trừ khi bạn sử dụng một số Perl ma thuật đen, nhưng chúng tôi đã thắng 't đi vào đó ở đây)

Nhưng Regex và chia là bạn của bạn.

+0

mà tôi hiểu ...
thực sự những gì tôi muốn cuối cùng là @parts nên chứa (1,2,3,4,5,6,8)
tương đương với (1,,6,8) – sud03r

0
@arr2 = (eval $str) ; 

Hoạt động, mặc dù tất nhiên bạn phải rất cẩn thận với eval().

+0

thanx ... tôi chỉ cần – sud03r

-1

Bạn có thể sử dụng eval:

$str = "1..15,16" ; 
@arr2 = (eval $str) ; 
@arr = (1..15,16) ; 
print "@arr\n" ; 
print "@arr2\n" ; 

Mặc dù nếu điều này là sử dụng đầu vào, có thể bạn sẽ muốn làm một số xác nhận trên chuỗi đầu vào đầu tiên, để đảm bảo họ có bất cứ điều gì không đầu vào tinh ranh.

1

Bạn đang nghĩ đến @arr2 = eval($str); Vì bạn đang dùng đầu vào và đánh giá điều đó, bạn cần phải cẩn thận. Có lẽ bạn nên @arr2 = eval($str) if ($str =~ m/^[0-9.,]+$/)

P.S. Tôi không biết về gói Number :: Range, nhưng nó là awesome. Số :: Phạm vi ftw.

1

Tôi đã gặp vấn đề tương tự khi xử lý kết quả của Bit :: Vector :: to_Enum. Tôi giải quyết nó bằng cách làm:

$range_string =~ s/\b(\d+)-(\d+)\b/expand_range($1,$2)/eg; 

sau đó cũng trong tập tin của tôi:

sub expand_range 
{ 
    return join(",",($_[0] .. $_[1])); 
} 

Vì vậy, "1,3,5-7,9,12-15" biến thành "1,3,5 , 6,7,9,12,13,14,15 ".

Tôi đã cố gắng thực sự để mở rộng trong phần thứ hai của s /// vì vậy tôi sẽ không cần chức năng bổ sung đó, nhưng tôi không thể làm cho nó hoạt động. Tôi thích điều này vì trong khi Number :: Range sẽ hoạt động, theo cách này tôi không phải kéo vào một mô-đun khác cho một thứ gì đó không đáng kể.

Các vấn đề liên quan