2010-01-26 31 views
15

Tôi gặp vấn đề lạ khi làm việc với hàm Javascript Regexp.exec. Khi gọi nhiều lần hàm trên đối tượng regexp mới (tôi đoán ...), nó hoạt động một lần mỗi hai lần. Tôi không hiểu tại sao!Javascript Regex bằng/g được sử dụng nhiều lần

Dưới đây là một ví dụ về vòng lặp nhỏ nhưng nó thực hiện tương tự khi được sử dụng một lần trong một hàm và được gọi nhiều lần.

for (var i = 0; i < 5; ++i) { 
    console.log(i, (/(b)/g).exec('abc')); 
} 

> 0 ["b", "b"] 
> 1 null 
> 2 ["b", "b"] 
> 3 null 
> 4 ["b", "b"] 

Khi xóa/g, nó trở lại bình thường.

for (var i = 0; i < 5; ++i) { 
    console.log(i, (/(b)/).exec('abc')); 
}    /* no g^*/ 

> 0 ["b", "b"] 
> 1 ["b", "b"] 
> 2 ["b", "b"] 
> 3 ["b", "b"] 
> 4 ["b", "b"] 

Tôi đoán rằng có tối ưu hóa, lưu đối tượng regexp, nhưng có vẻ lạ.

Hành vi này giống nhau trên Chrome 4 và Firefox 3.6, tuy nhiên nó hoạt động như (I) dự kiến ​​trong IE8. Tôi tin rằng đó là dự định nhưng tôi không thể tìm thấy logic trong đó, có thể bạn sẽ có thể giúp tôi!

Cảm ơn

+6

Các obj regexp tương tự đang được tái sử dụng bên trong vòng lặp của bạn có, và 'lastIndex' reset cho' 0' sau khi không khớp với bất kỳ thứ gì lặp lại lần thứ 2. Xem http://stackoverflow.com/questions/1760192/which-way-is-better-to-define-javascript-regular-expressions/1760506#1760506 để biết rõ về "lỗi" này. –

+1

tôi nghĩ rằng sự cố này có thể đã được khắc phục ngay bây giờ. cus tôi nhận được sản lượng chính xác từ cả hai cách trong moz, chrome và tức là. ai đó có thể đưa ra bất kỳ lời giải thích cho điều này? –

Trả lời

15

/gis not intended to work for simple matching:

/g phép "toàn cầu" phù hợp. Khi sử dụng phương thức replace(), hãy chỉ định công cụ sửa đổi này để thay thế tất cả các kết quả phù hợp, thay vì chỉ là kết quả đầu tiên.

Tôi muốn tưởng tượng nội javascript giữ phù hợp sau khi chụp, vì vậy nó sẽ có thể tiếp tục phù hợp và do đó null được trả về từ b xảy ra một lần duy nhất trong chủ đề. Hãy so sánh:

for (var i = 0; i < 5; ++i) { 
    console.log(i +' ' + (/(b+)/g).exec("abbcb")); 
} 

lợi nhuận:

0 bb,bb 
1 b,b 
2 null 
3 bb,bb 
4 b,b 
+0

Tùy thuộc vào "khớp đơn giản" nghĩa là gì, tùy chọn "g" có ý nghĩa hoàn hảo với "exec". Trong trường hợp này, ví dụ, nếu chuỗi kiểm tra có nhiều ký tự "b" trong đó, mảng kết quả sẽ có tất cả chúng. – Pointy

+0

@Pointy: đơn giản như trong "không thay thế". Và như mã của tôi rõ ràng cho thấy nó không hoạt động theo cách này – SilentGhost

+0

OK, bạn cũng nhầm. Cờ "g" rất hữu ích ngay cả khi không thực hiện thao tác "thay thế".Ví dụ, tôi có thể muốn lấy tất cả các số ra khỏi một câu: /(\d+)/g.exec(sentence). – Pointy

15

Nếu bạn đang đi để tái sử dụng các biểu thức chính quy cùng dù sao, mang nó ra khỏi vòng lặp và rõ ràng đặt lại:

var pattern = /(b)/g; 
for (var i = 0; i < 5; ++i) { 
    pattern.lastIndex = 0; 
    console.log(i + ' ' + pattern.exec("abc")); 
} 
+0

Đây có lẽ là cách tốt nhất để làm điều này, nhưng chỉ hoạt động nếu bạn đang thiết lập regex thành một var và không sử dụng nó inline như poster là (I E. '(/(b)/g).lastIndex = 0' sẽ * không * hoạt động) –

2

Cảm ơn :)

Tôi đã tìm thấy một tác động phụ thú vị, có thể tạo một biến tĩnh (theo nghĩa C, toàn cầu nhưng trên ly có thể nhìn thấy từ chức năng) mà không đóng cửa!

function test() { 
    var static = /a/g; 
    if ('count' in static) { 
     static.count++; 
    } else { 
     static.count = 1; 
    } 
    console.log(static.count); 
    } 

    for (var i = 0; i < 5; ++i) { test(); } 
    1 
    2 
    3 
    4 
    5 

(Tôi đang làm cho một câu trả lời mới, vì chúng ta không thể đặt mã bên trong một bình luận)

+0

Đây không phải là một bất ngờ. Các phần được mã hóa trong các cấu trúc như các vòng "cho" không phải là phạm vi từ vựng mới trong Javascript. Nói cách khác, hiệu ứng của vị trí của câu lệnh "var" bên trong vòng lặp chính xác giống như đặt nó ở phần đầu của khối chức năng xung quanh. – Pointy

+0

Hành vi này khác nhau trong IE, vì IE về cách IE xử lý regex khác nhau. Trong biểu thức regex nội tuyến của Chrome/Safari/FF được coi là toàn cầu mặc dù chúng được định nghĩa cục bộ dưới dạng biến. Trong IE, mỗi tệp được tạo thành một regex mới, do đó bạn in 1 1 1 1 1 thay vì 1 2 3 4 5 –

+0

Có lẽ bạn nên thay đổi tên của biến tĩnh, 'tĩnh' là một từ dành riêng trong JavaScript mặc dù nó là hiện không phải là từ khóa – codebox

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