2012-07-29 31 views
6

Tôi đã viết một tập lệnh Perl nhỏ với các cụm từ thông dụng để nhận các thành phần HTML của trang web.Vòng lặp vô hạn bằng cách sử dụng cặp đối sánh Perl regex

Tôi biết đây không phải là cách tốt để thực hiện loại công việc này, nhưng tôi đang cố gắng kiểm tra kỹ năng regex của mình.

Khi chạy với một trong hai mẫu regex trong vòng lặp while nó chạy hoàn hảo và hiển thị đầu ra chính xác. Nhưng khi tôi cố gắng kiểm tra cả hai mẫu trong vòng lặp while thì mẫu thứ hai khớp với mọi thời gian và vòng lặp chạy vô hạn.

kịch bản của tôi:

#!/usr/bin/perl -w 
use strict; 

while (<STDIN>) { 

    while ((m/<span class=\"itempp\">([^<]+)+?<\/span>/g) || 
      (m/<font size=\"-1\">([^<]+)+?<\/font>/g)) { 
     print "$1\n"; 
    } 
} 

Tôi đang thử nghiệm các kịch bản ở trên với một đầu vào mẫu:

<a href="http://linkTest">Link title</a> 
<span class="itempp">$150</span> 
<font size="-1"> (Location)</font> 

đầu ra mong muốn:

$150 
(Location) 

Cảm ơn bạn! Bất cứ sự giúp đỡ nào cũng được đánh giá cao!

+0

Bạn sẽ phải tiếp cận điều này một cách khác nếu bạn đang xử lý nhiều dòng. Khi bạn xử lý dòng STDIN khôn ngoan bên trong của bạn trong khi vẫn làm cho vô dụng. Sử dụng trình phân tích cú pháp HTML sẽ là giải pháp dễ bị lỗi nhất. Bạn cũng có thể thử kết hợp các khối với toán tử flipflop '..' –

+0

@mugenkenichi: Vô nghĩa. 'While' bên ngoài lặp lại trên các dòng của tệp và phần tử bên trong lặp lại qua các lần xuất hiện của mẫu trong dòng. Tại sao nội tâm 'trong khi' vô dụng? – Borodin

+0

Nếu bạn đang xử lý nhiều dòng .. Tôi có nghĩa là nếu thẻ bắt đầu nằm trên một dòng khác với thẻ đóng. Dù sao, tất cả những trường hợp đó sẽ được xử lý tốt hơn với một trình phân tích cú pháp chuyên biệt. –

Trả lời

9

Bất cứ khi nào một regex toàn cục không khớp với nó sẽ đặt lại vị trí nơi regex toàn cầu tiếp theo sẽ bắt đầu tìm kiếm. Vì vậy, khi lần đầu tiên trong hai mẫu của bạn thất bại, nó sẽ buộc thứ hai nhìn từ đầu chuỗi một lần nữa.

Hành vi này có thể bị tắt bằng cách thêm công cụ sửa đổi /c, làm cho vị trí không thay đổi nếu regex không khớp.

Bên cạnh đó, bạn có thể cải thiện mô hình của bạn bằng cách loại bỏ các ký tự thoát (" không cần thoát và / không cần phải được thoát nếu bạn chọn một delimiter khác nhau) và thừa +? sau khi chụp.

Cũng use warnings tốt hơn nhiều so với -w trên dòng lệnh.

Đây là phiên bản hoạt động của mã của bạn.

use strict; 
use warnings; 

while (<STDIN>) { 

    while(m|<span class="itempp">([^<]+)</span>|gc 
      or m|<font size="-1">([^<]+)</font>|gc) { 
     print "$1\n"; 
    } 
} 
+2

+1 để thực sự giải thích lý do mã OP bị lỗi. –

+0

tuyệt vời! Tôi không hoàn toàn tốt với perl. Tôi đang cố gắng học bởi vì nó rất dễ làm việc với mọi thứ. Cảm ơn bạn đã giải thích câu trả lời rõ ràng và chính xác – javaCity

+0

Trên lưu ý đó, tôi đã luôn luôn cố gắng học regex nhưng mặc dù tôi biết những thứ cơ bản như '?' Làm gì và tất cả, tôi không biết cách thực hiện đúng cách này. Có lời khuyên nào không? Cảm ơn! – javaCity

-3

Bạn không thay đổi $_ sau hoặc trong khi khớp, do đó, nó sẽ luôn khớp và chạy vào vòng lặp vô hạn.

để sửa lỗi, bạn có thể thêm $_=$'; sau print, để chạy lại khớp trong phần còn lại của chuỗi.

+0

cảm ơn bạn! tại sao rất nhiều downvotes mặc dù? – javaCity

+2

Bởi vì gán cho '$ _' là một ý tưởng tồi. Đặc biệt nếu nó chỉ là không cần thiết. Loại thủ thuật bẩn này nên tránh trừ khi bạn biết chắc chắn mình đang làm gì và tại sao bạn cần. –

+0

cảm ơn bạn đã làm rõ. – javaCity

3
while (<DATA>) { 
    if (m{<(?:span class="itempp"|font size="-1")>\s*([^<]+)}i) { 
     print "$1\n"; 
    } 
} 

__DATA__ 
<a href="http://linkTest">Link title</a> 
<span class="itempp">$150</span> 
<font size="-1"> (Location)</font> 
+0

tôi xin lỗi vì tôi đã phải thay đổi 'câu trả lời đúng' vì @Borodin đã cung cấp câu trả lời được giải thích tốt cho vấn đề. Cảm ơn bạn đã nỗ lực của bạn mặc dù. – javaCity

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