Tạo RegExps nhanh chóng bằng cách sử dụng các biến chuỗi


138

Nói rằng tôi muốn làm cho có thể sử dụng lại sau đây:

function replace_foo(target, replacement) {
   return target.replace("string_to_replace",replacement);
}

Tôi có thể làm một cái gì đó như thế này:

function replace_foo(target, string_to_replace, replacement) {
   return target.replace(string_to_replace,replacement);
}

Với chuỗi ký tự này là đủ dễ dàng. Nhưng nếu tôi muốn có thêm một chút khó khăn với regex thì sao? Ví dụ, nói rằng tôi muốn thay thế mọi thứ nhưng string_to_replace . Theo bản năng, tôi sẽ cố gắng mở rộng những điều trên bằng cách làm một cái gì đó như:

function replace_foo(target, string_to_replace, replacement) {
   return target.replace(/^string_to_replace/,replacement);
}

Điều này dường như không hoạt động. Tôi đoán là nó nghĩ string_to_replacelà một chuỗi bằng chữ, chứ không phải là một biến đại diện cho một chuỗi. Có thể tạo regexes JavaScript một cách nhanh chóng bằng cách sử dụng các biến chuỗi không? Một cái gì đó như thế này sẽ là tuyệt vời nếu có thể:

function replace_foo(target, string_to_replace, replacement) {
   var regex = "/^" + string_to_replace + "/";
   return target.replace(regex,replacement);
}

Câu trả lời:


215

new RegExp(string, flags)nơi flagsghay i. Vì thế

'GODzilla'.replace( new RegExp('god', 'i'), '' )

đánh giá

zilla

31
Và bỏ qua các /dấu phân cách regex khi sử dụng biểu mẫu này.
cdhowie

111

Với chuỗi ký tự này là đủ dễ dàng.

Không hẳn vậy! Ví dụ chỉ thay thế sự xuất hiện đầu tiên của string_to_replace. Thông thường hơn, bạn muốn thay thế tất cả các lần xuất hiện, trong trường hợp đó, bạn phải chuyển đổi chuỗi thành /.../gRegExp toàn cầu ( ). Bạn có thể làm điều này từ một chuỗi bằng cách sử dụng hàm new RegExptạo:

new RegExp(string_to_replace, 'g')

Vấn đề với điều này là bất kỳ ký tự đặc biệt regex nào trong chuỗi ký tự sẽ hành xử theo cách đặc biệt của chúng thay vì là các ký tự bình thường. Bạn sẽ phải gạch chéo lại - thoát chúng để khắc phục điều đó. Thật không may, không có chức năng tích hợp sẵn để làm điều này cho bạn, vì vậy đây là một chức năng bạn có thể sử dụng:

function escapeRegExp(s) {
    return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
}

Cũng lưu ý rằng khi bạn sử dụng RegExp replace(), chuỗi thay thế cũng có một ký tự đặc biệt $. Điều này cũng phải được thoát nếu bạn muốn có một chữ $trong văn bản thay thế của bạn!

function escapeSubstitute(s) {
    return s.replace(/\$/g, '$$$$');
}

(Bốn $giây vì đó là một chuỗi thay thế, argh!)

Bây giờ bạn có thể thực hiện thay thế chuỗi toàn cầu bằng RegExp:

function replace_foo(target, string_to_replace, replacement) {
    var relit= escapeRegExp(string_to_replace);
    var sub= escapeSubstitute(replacement);
    var re= new RegExp(relit, 'g');
    return target.replace(re, sub);
}

Thật là một nỗi đau. May mắn thay, nếu tất cả những gì bạn muốn làm là một chuỗi thẳng thay thế mà không có phần bổ sung nào của regex, có một cách nhanh hơn:

s.split(string_to_replace).join(replacement)

...và đó là tất cả. Đây là một thành ngữ thường được hiểu.

nói rằng tôi muốn thay thế mọi thứ trừ chuỗi_to numplace

Điều đó có nghĩa là gì, bạn muốn thay thế tất cả các đoạn văn bản không tham gia vào một trận đấu với chuỗi? Một sự thay thế bằng ^chắc chắn không phải điều này, bởi vì ^có nghĩa là mã thông báo bắt đầu, không phải là phủ định. ^chỉ là một phủ định trong []các nhóm nhân vật. Cũng có những cái nhìn tiêu cực (?!...), nhưng có những vấn đề với điều đó trong JScript vì vậy bạn thường nên tránh nó.

Bạn có thể thử khớp 'mọi thứ cho đến' chuỗi và sử dụng hàm để loại bỏ bất kỳ khoảng trống nào giữa các chuỗi khớp:

var re= new RegExp('(.*)($|'+escapeRegExp(string_to_find)+')')
return target.replace(re, function(match) {
    return match[1]===''? match[2] : replacement+match[2];
});

Ở đây, một lần nữa, việc phân chia có thể đơn giản hơn:

var parts= target.split(string_to_match);
for (var i= parts.length; i-->0;)
    if (parts[i]!=='')
        parts[i]= replacement;
return parts.join(string_to_match);

10

Như những người khác đã nói, sử dụng new RegExp(pattern, flags)để làm điều này. Điều đáng chú ý là bạn sẽ chuyển chuỗi ký tự chuỗi vào hàm tạo này, vì vậy mọi dấu gạch chéo ngược sẽ phải được thoát. Ví dụ, nếu bạn muốn regex của bạn khớp với dấu gạch chéo ngược, bạn sẽ cần phải nói new RegExp('\\\\'), trong khi chữ regex chỉ cần có /\\/. Tùy thuộc vào cách bạn định sử dụng cái này, bạn nên cảnh giác chuyển đầu vào của người dùng vào một chức năng như vậy mà không xử lý trước đầy đủ (thoát các ký tự đặc biệt, v.v.) Nếu không có điều này, người dùng của bạn có thể nhận được một số kết quả rất bất ngờ.


3
Câu trả lời này, trong khi không phải là chi tiết nhất, lại đề cập đến một chi tiết quan trọng mà tôi đã bị mắc kẹt trong một giờ: thoát khỏi bất kỳ chuỗi đặc biệt nào. Ví dụ, tôi đang tìm kiếm một từ bắt đầu bằng một thuật ngữ nhất định, vì vậy regex tôi cần là /\b[term]\B/, nhưng khi xây dựng nó tôi cần gọi new RegExp("\\b"+ term + "\\B"). Sự khác biệt nhỏ nhưng quan trọng và khó nhận ra kể từ khi sử dụng nó như một biểu thức chính trực tiếp làm việc như mong đợi.
Byson


0

Tôi nghĩ rằng tôi có ví dụ rất hay cho văn bản nổi bật trong chuỗi (nó thấy không nhìn vào thanh ghi mà được tô sáng bằng cách sử dụng thanh ghi)

function getHighlightedText(basicString, filterString) {

    if ((basicString === "") || (basicString === null) || (filterString === "") || (filterString === null)) return basicString;

    return basicString.replace(new RegExp(filterString.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\\\$&'), 'gi'),
        function(match)
            {return "<mark>"+match+"</mark>"});

}

http://jsfiddle.net/cdbzL/1258/


0

Một giải pháp thực sự đơn giản cho việc này là:

function replace(target, string_to_replace, replacement) {
  return target.split(string_to_replace).join(replacement);
}

Không cần Regexes chút nào

Nó dường như cũng là nhanh nhất trên các trình duyệt hiện đại https://jsperf.com/replace-vs-split-join-vs-replaceall

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.