RegExp.exec () trả về NULL không thường xuyên


83

Tôi thực sự phát điên vì điều này và tôi đã dành một khoảng thời gian không cân xứng để cố gắng tìm ra những gì đang xảy ra ở đây. Vì vậy, hãy giúp tôi một tay =)

Tôi cần thực hiện một số đối sánh RegExp của các chuỗi trong JavaScript. Thật không may, nó cư xử rất kỳ lạ. Mã này:

var rx = /(cat|dog)/gi;
var w = new Array("I have a cat and a dog too.", "There once was a dog and a cat.", "I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.");

for (var i in w) {
    var m = null;
    m = rx.exec(w[i]);
    if(m){
        document.writeln("<pre>" + i + "\nINPUT: " + w[i] + "\nMATCHES: " + m.slice(1) + "</pre>");
    }else{
        document.writeln("<pre>" + i + "\n'" + w[i] + "' FAILED.</pre>");
    }
}

Trả về "cat" và "dog" cho hai phần tử đầu tiên, như nó phải như vậy, nhưng sau đó một số- exec()cuộc gọi bắt đầu trả về null. Tôi không hiểu tại sao.

Tôi đã đăng một Fiddle ở đây , nơi bạn có thể chạy và chỉnh sửa mã.

Và cho đến nay tôi đã thử điều này trong Chrome và Firefox.

Chúc mừng!

/ Christofer


nó chỉ thất bại trên một "I have a cat and a dog too.", có vẻ như
SilentGhost

thi hành trả về null nếu một kết quả không khớp theo thiết kế, vì vậy vì lý do nào đó mà nó không khớp.
Martin Jespersen

Câu trả lời:


79

Ồ, nó đây. Bởi vì bạn đang xác định toàn cầu regex của mình, nó khớp đầu tiên catvà ở lần vượt qua thứ hai của vòng lặp dog. Vì vậy, về cơ bản bạn chỉ cần đặt lại regex của mình (đó là con trỏ nội bộ). Cf điều này:

var w = new Array("I have a cat and a dog too.", "I have a cat and a dog too.", "I have a cat and a dog too.", "I have a cat and a dog too.");

for (var i in w) {
    var rx = /(cat|dog)/gi;
    var m = null;
    m = rx.exec(w[i]);
    if(m){
        document.writeln("<p>" + i + "<br/>INPUT: " + w[i] + "<br/>MATCHES: " + w[i].length + "</p>");
    }else{
        document.writeln("<p><b>" + i + "<br/>'" + w[i] + "' FAILED.</b><br/>" + w[i].length + "</p>");
    }
    document.writeln(m);
}

ở đó chúng tôi có nó, tôi đã quá chậm :)
Martin Jespersen

à ngọt ngào! Tôi sẽ mất một lúc để tìm ra điều đó. cảm ơn!
cpak

Điều này đã tiết kiệm cho tôi rất nhiều thời gian. Cám ơn rất nhiều!
Thomas Johansen

Vấn đề này khiến tôi nghi ngờ cuộc sống.
GZ Xue,

Tôi cảm thấy như tôi chỉ nên cung cấp lương lưng tôi
cgatian

72

Đối tượng regex có một thuộc tính lastIndexđược cập nhật khi bạn chạy exec. Vì vậy, khi bạn thực thi regex trên ví dụ: "Tôi cũng có một con mèo và một con chó.", lastIndexĐược đặt thành 12. Lần tiếp theo bạn chạy exectrên cùng một đối tượng regex, nó bắt đầu tìm kiếm từ chỉ mục 12. Vì vậy, bạn phải đặt lại thuộc lastIndextính giữa mỗi lần chạy.


Bah, trang web này quá nhanh đối với tôi. +1 cho SilentGhost :-)
Frode

8
Cảm ơn vì lời giải thích! Nó giúp ích rất nhiều bằng cách thiết lập myRe.lastIndex = 0;để sử dụng tiếp theo.
Antony

1
Chà, cảm ơn rất nhiều vì gợi ý với lastIndex, điều đó thực sự khiến tôi phát điên!
dave0688

1
Tôi nghĩ rằng đây sẽ là câu trả lời đúng vì nó theo các thực hành tốt nhất của tái sử dụng các đối tượng regex cùng
smurtagh

Đồng ý rằng đây phải là câu trả lời chính xác. Nó sử dụng lại cùng một đối tượng regex và cũng giải thích cơ học bên trong. OP nên xem xét thay đổi.
Sean Coley

31

Hai điều:

  1. Cần đề cập đến việc đặt lại khi sử dụng gcờ (toàn cầu). Để giải quyết điều này, tôi đề nghị chỉ cần gán 0cho lastIndexthành viên của RegExpđối tượng. Điều này có hiệu suất tốt hơn so với tiêu diệt và tái tạo.
  2. Hãy cẩn thận khi sử dụng intừ khóa để đi mộtArray đối tượng, vì có thể dẫn đến kết quả không mong muốn với một số lib. Đôi khi bạn nên kiểm tra bằng somethign như isNaN(i), hoặc nếu bạn biết nó không có lỗ, hãy sử dụng vòng lặp for cổ điển.

Mã có thể là:

var rx = /(cat|dog)/gi;
w = ["I have a cat and a dog too.", "There once was a dog and a cat.", "I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat."];

for (var i in w)
 if(!isNaN(i))        // Optional, check it is an element if Array could have some odd members.
  {
   var m = null;
   m = rx.exec(w[i]); // Run
   rx.lastIndex = 0;  // Reset
   if(m)
    {
     document.writeln("<pre>" + i + "\nINPUT: " + w[i] + "\nMATCHES: " + m.slice(1) + "</pre>");
    } else {
     document.writeln("<pre>" + i + "\n'" + w[i] + "' FAILED.</pre>");
    }
  }

1
Đây phải là câu trả lời chính xác. Thiết lập rx.lastIndex = 0tốt hơn nhiều so với việc tạo lại đối tượng RegEx bên trong vòng lặp.
Minoru

4

Tôi đã gặp sự cố tương tự khi chỉ sử dụng / g và giải pháp được đề xuất ở đây không hoạt động với tôi trong FireFox 3.6.8. Tôi đã làm việc với tập lệnh của mình

var myRegex = new RegExp("my string", "g");

Tôi thêm điều này trong trường hợp ai đó gặp vấn đề tương tự như tôi đã làm với giải pháp trên.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.