2012-06-13 37 views
12

thể trùng lặp:
Interesting test of Javascript RegExp
Regular expression test can't decide between true and false (JavaScript)Tại sao cùng một RegExp hoạt động khác nhau?

Example of issue. Khi chạy nội tuyến các kết quả như tôi mong đợi. Nhưng khi được lưu trữ như một biến nó bỏ qua phần tử span giữa.

// Inline RegExp 
function getToggleClasses() { 
    var toggler = [], 
     elements = document.getElementsByTagName("*"), 
     i=0, 
     len = elements.length; 

    for (i; i < len; i++) { 
    if (/toggler/g.test(elements[i].className)) { 
     toggler.push(elements[i]); 
    } 
    } 

    document.getElementById('results').innerHTML += "<br />Inline: " + toggler.length; 
} 

// Variable 
function getToggleClasses2() { 
    var toggler = [], 
     elements = document.getElementsByTagName("*"), 
     tester = /toggler/g, 
     i=0, 
     len = elements.length; 

    for (i; i < len; i++) { 
    if (tester.test(elements[i].className)) { 
     toggler.push(elements[i]); 
    } 
    } 

    document.getElementById('results').innerHTML += "<br />Variable: " + toggler.length; 
} 
​ 

Đánh dấu lên:

<span class="toggler">A</span> 
<span class="toggler">B</span> 
<span class="toggler">C</span> 

Với: tôi hiểu không có lý do để sử dụng một RegExp để làm so sánh này và tôi cũng hiểu làm thế nào các thư viện lớn như jQuery là. Tôi cũng biết rằng không cần phải có g trong trường hợp này.

Tôi không thể hiểu tại sao hai phương pháp này nên trả về các kết quả khác nhau.

+0

Đây chỉ là sở thích cá nhân, nhưng tôi nghĩ rằng nó sẽ cải thiện rõ ràng một chút để đặt dấu ngoặc đơn xung quanh một chữ regex có cờ khi gọi một hàm trên chữ. – JAB

+1

@apsillers, bạn là chính xác. Bạn đã tìm kiếm những gì? Tôi không thể tìm ra những gì để tìm kiếm để có được kết quả sau đó. – Joe

+0

Tôi lừa một chút và tìm kiếm '[javascript] kiểm tra regex lastindex' - tôi khá chắc chắn rằng một câu hỏi như thế này đã được hỏi trước đây, và tôi biết câu trả lời sẽ bao gồm văn bản' lastIndex'. Đây là một trường hợp tốt cho thấy rằng sự tồn tại của một câu hỏi trùng lặp không nhất thiết là một dấu hiệu cho thấy người hỏi đã cẩu thả; bạn đã hỏi một câu hỏi thích hợp cho một vấn đề khó tìm kiếm. – apsillers

Trả lời

9

RegExp trường là stateful, vì vậy tái sử dụng chúng có thể gây ra hành vi bất ngờ. Trong trường hợp cụ thể này, đó là vì cá thể là global, có nghĩa là:

rằng cụm từ thông dụng phải được kiểm tra đối với tất cả các kết hợp có thể có trong chuỗi.

Tuy nhiên, đó không phải là sự khác biệt duy nhất do sử dụng g. From RegExp.test @ MDN:

Như với exec (hoặc kết hợp với nó), test gọi nhiều lần trên các trường hợp biểu thức chính quy toàn cầu tương tự sẽ thúc đẩy quá khứ trận đấu trước đó.


Remove the g flag, hoặc set lastIndex to 0 (nhờ, @zzzzBov).

+3

hoặc đặt 'lastIndex' thành' 0' ... – zzzzBov

+0

@zzzzBov điểm tốt, được chỉnh sửa. –

3

/gkhông cần thiết và không nên sử dụng trong trường hợp này.

Hành vi khác nhau trong những trường hợp này vì trong trường hợp "nội tuyến" đối tượng regex được tạo lại mỗi lần lặp của vòng lặp. Trong khi trong biến được tạo ra một lần, và giữ trạng thái của nó (lastIndex) giữa các lần lặp vòng lặp.

Di chuyển var vào vòng lặp và bạn sẽ nhận được kết quả tương tự:

// Variable 
function getToggleClasses2() { 
    var toggler = [], 
     elements = document.getElementsByTagName("*"), 
     i=0, 
     len = elements.length; 

    for (i; i < len; i++) { 
    var tester = /toggler/g; 
    if (tester.test(elements[i].className)) { 
     toggler.push(elements[i]); 
    } 
    } 

    document.getElementById('results').innerHTML += "<br />Variable: " + toggler.length; 
} 
+1

Vâng, tôi hiểu rồi. Nhưng tại sao những gì tôi rất tò mò muốn biết. Bởi vì '/toggler/g.test('toggler '); // true' – Joe

+1

@Joe, giải thích. – Qtax

+1

@Joe, bạn đã viết trong câu hỏi * "Tôi cũng biết rằng' g' là cần thiết "*, đó là lý do tại sao tôi nói rằng nó không phải. – Qtax

1

Regex duy trì một biến được gọi là lastIndex, là chỉ mục để bắt đầu tìm kiếm tiếp theo. Từ MDN:

Như với exec (hoặc kết hợp với nó), test gọi nhiều lần trên các trường hợp biểu thức chính quy toàn cầu tương tự sẽ thúc đẩy quá khứ trận đấu trước đó.

Khi bạn xác định regex nội tuyến cho mỗi lần lặp lại, trạng thái bị mất và lastIndex luôn là 0 vì bạn có regex mới mỗi lần. Nếu bạn giữ regex trong một veriable, các lastIndex được lưu như là vị trí kết thúc của trận đấu cuối cùng, mà trong trường hợp này gây ra các tìm kiếm tiếp theo để bắt đầu ở cuối của chuỗi tiếp theo, dẫn đến một trận đấu không thành công. Khi so sánh thứ ba đến xung quanh, lastIndex đã được đặt lại về 0 vì regex biết rằng nó không có kết quả lần trước.

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