สร้าง RegExps ได้ทันทีโดยใช้ตัวแปรสตริง


138

ว่าฉันต้องการทำให้สามารถใช้งานได้ดังต่อไปนี้:

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

ฉันอาจทำสิ่งนี้:

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

ด้วยตัวอักษรสตริงนี้ง่ายพอ แต่ถ้าฉันต้องการเพิ่มความยุ่งยากเล็กน้อยกับ regex? ตัวอย่างเช่นพูดว่าฉันต้องการแทนที่ทุกอย่างแต่ string_to_replaceแต่โดยสัญชาตญาณฉันพยายามที่จะขยายด้านบนโดยทำสิ่งที่ชอบ:

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

ดูเหมือนจะใช้งานไม่ได้ ฉันเดาว่ามันคิดว่าstring_to_replaceเป็นตัวอักษรสตริงมากกว่าตัวแปรที่เป็นตัวแทนของสตริง เป็นไปได้หรือไม่ที่จะสร้าง JavaScript regexes ได้ทันทีโดยใช้ตัวแปรสตริง สิ่งนี้จะดีถ้าเป็นไปได้ทั้งหมด:

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

คำตอบ:


215

มีnew RegExp(string, flags)ที่flagsอยู่หรือg iดังนั้น

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

ประเมินให้

zilla

31
และละเว้น/ตัวคั่น regex เมื่อใช้แบบฟอร์มนี้ด้วย
cdhowie

111

ด้วยตัวอักษรสตริงนี้ง่ายพอ

ไม่ได้จริงๆ! ตัวอย่างจะแทนที่การเกิดขึ้นครั้งแรกstring_to_replaceเท่านั้น โดยทั่วไปคุณต้องการแทนที่เหตุการณ์ทั้งหมดซึ่งในกรณีนี้คุณต้องแปลงสตริงเป็น global ( /.../g) RegExp คุณสามารถทำได้จากสตริงโดยใช้ตัวnew RegExpสร้าง:

new RegExp(string_to_replace, 'g')

ปัญหานี้คือตัวอักษรพิเศษใด ๆ regex ในตัวอักษรสตริงจะทำงานในรูปแบบพิเศษของพวกเขาแทนที่จะเป็นตัวอักษรปกติ คุณจะต้องแบ็กสแลช - หลบหนีเพื่อแก้ไข น่าเสียดายที่ไม่มีฟังก์ชั่นในตัวที่จะทำสิ่งนี้ให้คุณดังนั้นนี่คือฟังก์ชันที่คุณสามารถใช้:

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

โปรดทราบว่าเมื่อคุณใช้ RegExp ในreplace()ตอนนี้สตริงการแทนที่จะมีอักขระพิเศษเช่น$กัน สิ่งนี้จะต้องถูกหลบหนีหากคุณต้องการให้มีตัวอักษร$อยู่ในข้อความที่ถูกแทนที่!

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

(สี่ $ s เพราะนั่นคือตัวเองสตริงแทนที่ - argh!)

ตอนนี้คุณสามารถใช้การแทนที่สตริงส่วนกลางด้วย 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);
}

ช่างเจ็บปวดเหลือเกิน โชคดีถ้าสิ่งที่คุณต้องการทำคือการแทนที่สตริงแบบตรงโดยไม่มีส่วนเพิ่มเติมของ regex มีวิธีที่เร็วกว่า:

s.split(string_to_replace).join(replacement)

... และนั่นคือทั้งหมด นี่เป็นสำนวนที่เข้าใจกันทั่วไป

บอกว่าฉันต้องการแทนที่ทุกอย่าง แต่ string_to_replace

หมายความว่าคุณต้องการแทนที่ข้อความทั้งหมดที่ไม่ได้มีส่วนร่วมในการแข่งขันกับสตริง? การแทนที่ด้วยสิ่ง^นี้ไม่ได้เป็นอย่างแน่นอนเพราะ^หมายถึงโทเค็นเริ่มต้นของสตริงไม่ใช่การปฏิเสธ ^เป็นเพียงการปฏิเสธใน[]กลุ่มตัวละคร นอกจากนี้ยังมี lookaheads เชิงลบ(?!...)แต่มีปัญหาใน JScript ดังนั้นโดยทั่วไปคุณควรหลีกเลี่ยง

คุณอาจลองจับคู่ 'ทุกอย่างจนถึงสตริง' และใช้ฟังก์ชันเพื่อยกเลิกการเว้นว่างระหว่างสตริงที่ตรงกัน:

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

ที่นี่อีกครั้งการแบ่งอาจง่ายกว่า:

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

อย่างที่คนอื่น ๆ พูดใช้new RegExp(pattern, flags)ทำสิ่งนี้ เป็นที่น่าสังเกตว่าคุณจะส่งตัวอักษรสตริงไปยังตัวสร้างนี้ดังนั้นเครื่องหมายแบ็กสแลชทุกอันจะต้องถูกหลบหนี ตัวอย่างเช่นถ้าคุณต้องการให้ regex ของคุณจับคู่แบ็กสแลชคุณจะต้องพูดnew RegExp('\\\\')ในขณะที่ตัวอักษร regex จะต้องเป็น/\\/เท่านั้น ขึ้นอยู่กับว่าคุณตั้งใจจะใช้สิ่งนี้อย่างไรคุณควรระวังการส่งผ่านข้อมูลผู้ใช้ไปยังฟังก์ชั่นดังกล่าวโดยไม่ได้ทำการประมวลผลล่วงหน้าอย่างเพียงพอ (ยกเว้นอักขระพิเศษ ฯลฯ ) หากไม่มีสิ่งนี้ผู้ใช้ของคุณอาจได้รับผลลัพธ์


3
คำตอบนี้แม้ว่าจะไม่ได้รายละเอียดมากที่สุด แต่ก็พูดถึงรายละเอียดที่สำคัญซึ่งฉันเพิ่งติดขัดอยู่หนึ่งชั่วโมง: หลีกเลี่ยงลำดับพิเศษใด ๆ ยกตัวอย่างเช่นผมค้นหาคำที่เริ่มต้นด้วยคำบางอย่างเพื่อ regex ที่ฉันจะต้องเป็นแต่เมื่อสร้างมันฉันต้องโทร/\b[term]\B/ new RegExp("\\b"+ term + "\\B")ความแตกต่างเล็กน้อย แต่สำคัญและยากที่จะสังเกตเห็นเนื่องจากใช้เป็น regex โดยตรงจะทำงานได้ตามที่คาดไว้
Byson


0

ฉันคิดว่าฉันมีตัวอย่างที่ดีมากสำหรับข้อความที่เน้นในสตริง (พบว่าไม่ได้ดูที่การลงทะเบียน แต่ถูกเน้นโดยใช้การลงทะเบียน)

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

วิธีง่ายๆในการแก้ปัญหานี้คือ:

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

ไม่จำเป็นต้องใช้ Regexes เลย

ดูเหมือนว่าจะเร็วที่สุดในเบราว์เซอร์สมัยใหม่https://jsperf.com/replace-vs-split-join-vs-replaceall

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.