จะแยกนิพจน์ปกติที่มีความยาวออกเป็นหลายบรรทัดใน JavaScript ได้อย่างไร


138

ฉันมีนิพจน์ปกติที่ยาวมากซึ่งฉันต้องการแบ่งออกเป็นหลายบรรทัดในรหัส JavaScript ของฉันเพื่อให้แต่ละบรรทัดมีความยาว 80 บรรทัดตามกฎ JSLint ฉันคิดว่ามันดีกว่าสำหรับการอ่าน นี่คือตัวอย่างรูปแบบ:

var pattern = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

4
ดูเหมือนว่าคุณกำลังพยายามตรวจสอบที่อยู่อีเมล ทำไมไม่เพียงแค่ทำ/\S+@\S+\.\S+/?
Bart Kiers

1
คุณควรหาวิธีที่จะทำเช่นนั้นโดยไม่ต้องมีการแสดงออกปกติหรือมีการแสดงออกปกติขนาดเล็กหลาย นั่นจะสามารถอ่านได้มากกว่านิพจน์ทั่วไปที่มีความยาวมาก หากการแสดงออกปกติของคุณมากกว่า 20 ตัวอักษรอาจมีวิธีที่ดีกว่าที่จะทำ
ForbesLindesay

2
ทุกวันนี้มีตัวละคร 80 ตัวที่ล้าสมัยไปแล้วด้วยจอภาพกว้างใช่หรือไม่
Oleg V. Volkov

7
@ OlegV.Volkov ไม่บุคคลอาจใช้ split windows ใน vim ซึ่งเป็น terminal เสมือนในห้องเซิร์ฟเวอร์ มันผิดที่จะถือว่าทุกคนจะได้รับการเข้ารหัสในวิวพอร์ตเดียวกันกับคุณ นอกจากนี้การ จำกัด บรรทัดของคุณถึง 80 ตัวอักษรบังคับให้คุณแยกรหัสของคุณออกเป็นฟังก์ชันที่เล็กลง
synic

แน่นอนฉันเห็นแรงจูงใจของคุณที่ต้องการทำสิ่งนี้ที่นี่ - เมื่อ regex นี้ถูกแบ่งออกเป็นหลายบรรทัดดังที่ Koolilnc แสดงให้เห็นแล้วมันกลายเป็นตัวอย่างที่สมบูรณ์แบบของรหัสที่สามารถอ่านได้ด้วยตนเอง ¬_¬
Mark Amery

คำตอบ:


115

คุณสามารถแปลงเป็นสตริงและสร้างการแสดงออกโดยการโทรnew RegExp():

var myRE = new RegExp (['^(([^<>()[\]\\.,;:\\s@\"]+(\\.[^<>(),[\]\\.,;:\\s@\"]+)*)',
                        '|(\\".+\\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.',
                        '[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\\.)+',
                        '[a-zA-Z]{2,}))$'].join(''));

หมายเหตุ:

  1. เมื่อแปลงตัวอักษรแสดงออกสตริงคุณต้องหนี backslashes ทั้งหมดเป็นเครื่องหมายที่มีการบริโภคเมื่อการประเมินตามตัวอักษรสตริง (ดูความคิดเห็นของ Kayo สำหรับรายละเอียดเพิ่มเติม)
  2. RegExp ยอมรับโมดิฟายเออร์เป็นพารามิเตอร์ตัวที่สอง

    /regex/g => new RegExp('regex', 'g')

[ เพิ่มเติม ES20xx (เทมเพลตที่ติดแท็ก)]

ใน ES20xx คุณสามารถใช้เทมเพลตที่ติดแท็กได้ ดูตัวอย่าง

บันทึก:

  • ข้อเสียที่นี่เป็นที่คุณไม่สามารถใช้ช่องว่างธรรมดาในสตริงนิพจน์ปกติ (มักจะใช้\s, \s+, \s{1,x}, \t, \nฯลฯ )

(() => {
  const createRegExp = (str, opts) => 
    new RegExp(str.raw[0].replace(/\s/gm, ""), opts || "");
  const yourRE = createRegExp`
    ^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|
    (\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|
    (([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$`;
  console.log(yourRE);
  const anotherLongRE = createRegExp`
    (\byyyy\b)|(\bm\b)|(\bd\b)|(\bh\b)|(\bmi\b)|(\bs\b)|(\bms\b)|
    (\bwd\b)|(\bmm\b)|(\bdd\b)|(\bhh\b)|(\bMI\b)|(\bS\b)|(\bMS\b)|
    (\bM\b)|(\bMM\b)|(\bdow\b)|(\bDOW\b)
    ${"gi"}`;
  console.log(anotherLongRE);
})();


4
A new RegExpเป็นวิธีที่ยอดเยี่ยมสำหรับการแสดงออกปกติหลายบรรทัด แทนการเข้าร่วมอาร์เรย์คุณก็สามารถใช้ประกอบการสตริง:var reg = new RegExp('^([a-' + 'z]+)$','i');
dakab

43
ข้อควรระวัง: ตัวอักษรนิพจน์ทั่วไปที่ยาวอาจแบ่งเป็นหลายบรรทัด อย่างไรก็ตามจำเป็นต้องมีการดูแลเนื่องจากคุณไม่สามารถคัดลอกนิพจน์ปกติ (กำหนดด้วย//) และวางเป็นอาร์กิวเมนต์สตริงไปยังตัวสร้าง RegExp เพราะนี่คือตัวอักษรทับขวาได้รับการบริโภคเมื่อการประเมินตามตัวอักษรสตริง ตัวอย่าง: ไม่สามารถถูกแทนที่ด้วย/Hey\sthere/ new RegExp("Hey\sthere")แต่ควรแทนที่ด้วยnew RegExp("Hey\\sthere")หมายเหตุเครื่องหมายแบ็กสแลชพิเศษ! ดังนั้นฉันต้องการปล่อยให้ตัวอักษร regex ยาวในบรรทัดยาวหนึ่ง
Kayo

5
วิธีการที่ชัดเจนมากขึ้นการทำเช่นนี้คือการสร้างตัวแปรชื่อถือครองส่วนย่อยที่มีความหมายและเข้าร่วมเหล่านั้นเป็นสตริงหรือในอาร์เรย์ ที่ช่วยให้คุณสร้างRegExpในวิธีที่ง่ายต่อการเข้าใจ
Chris Krycho

117

การขยาย @KooiInc คำตอบคุณสามารถหลีกเลี่ยงการหลบหนีด้วยตัวละครพิเศษทุกตัวด้วยตนเองโดยใช้sourceคุณสมบัติของRegExpวัตถุ

ตัวอย่าง:

var urlRegex= new RegExp(''
  + /(?:(?:(https?|ftp):)?\/\/)/.source     // protocol
  + /(?:([^:\n\r]+):([^@\n\r]+)@)?/.source  // user:pass
  + /(?:(?:www\.)?([^\/\n\r]+))/.source     // domain
  + /(\/[^?\n\r]+)?/.source                 // request
  + /(\?[^#\n\r]*)?/.source                 // query
  + /(#?[^\n\r]*)?/.source                  // anchor
);

หรือถ้าคุณต้องการหลีกเลี่ยงการทำซ้ำ.sourceคุณสมบัติคุณสามารถทำได้โดยใช้Array.map()ฟังก์ชั่น:

var urlRegex= new RegExp([
  /(?:(?:(https?|ftp):)?\/\/)/      // protocol
  ,/(?:([^:\n\r]+):([^@\n\r]+)@)?/  // user:pass
  ,/(?:(?:www\.)?([^\/\n\r]+))/     // domain
  ,/(\/[^?\n\r]+)?/                 // request
  ,/(\?[^#\n\r]*)?/                 // query
  ,/(#?[^\n\r]*)?/                  // anchor
].map(function(r) {return r.source}).join(''));

ใน ES6 ฟังก์ชันแผนที่สามารถลดลงเป็น: .map(r => r.source)


3
สิ่งที่ฉันกำลังมองหานั้นสะอาดหมดจดจริงๆ ขอบคุณ!
Marian Zagoruiko

10
สิ่งนี้สะดวกสำหรับการเพิ่มความคิดเห็นไปยัง regexp ที่ยาว อย่างไรก็ตามมันถูก จำกัด โดยการจับคู่วงเล็บในบรรทัดเดียวกัน
Nathan S. Watson-Haigh

แน่นอนนี่! ดีมากกับความสามารถในการแสดงความคิดเห็นในแต่ละส่วนย่อย
GaryO

ขอบคุณมันช่วยวางแหล่งข้อมูลในฟังก์ชัน regex
รหัส

ฉลาดมาก. ขอบคุณความคิดนี้ช่วยฉันได้มาก เช่นเดียวกับบันทึกย่อด้านข้าง: ฉันได้สรุปสิ่งต่าง ๆ ทั้งหมดในฟังก์ชั่นเพื่อทำให้มันสะอาดยิ่งขึ้น: combineRegex = (...regex) => new RegExp(regex.map(r => r.source).join(""))การใช้งาน:combineRegex(/regex1/, /regex2/, ...)
Scindix

25

การใช้สตริงในnew RegExpนั้นน่าอึดอัดใจเพราะคุณต้องหลีกเลี่ยงแบ็กสแลชทั้งหมด คุณสามารถเขียน regex ที่เล็กลงและต่อมันได้

มาแบ่ง regex นี้กัน

/^foo(.*)\bar$/

เราจะใช้ฟังก์ชั่นเพื่อทำให้สิ่งสวยงามมากขึ้นในภายหลัง

function multilineRegExp(regs, options) {
    return new RegExp(regs.map(
        function(reg){ return reg.source; }
    ).join(''), options);
}

และตอนนี้เรามาเขย่า

var r = multilineRegExp([
     /^foo/,  // we can add comments too
     /(.*)/,
     /\bar$/
]);

เนื่องจากมีค่าใช้จ่ายพยายามสร้าง regex จริงเพียงครั้งเดียวแล้วใช้สิ่งนั้น


มันเจ๋งมาก - ไม่เพียง แต่คุณไม่ต้องทำการหลบหนีเพิ่มเติม แต่ยังให้ไฮไลท์ไวยากรณ์พิเศษสำหรับ sub-regexes!
quezak

หนึ่ง caveat แม้ว่า: คุณต้องให้แน่ใจว่า sub-regexes ของคุณอยู่ในตัวเองหรือห่อแต่ละในกลุ่มวงเล็บเหลี่ยมใหม่ ตัวอย่าง: multilineRegExp([/a|b/, /c|d])ผลในขณะที่คุณหมายถึง/a|bc|d/ (a|b)(c|d)
quezak

6

มีคำตอบที่ดีอยู่ที่นี่ แต่เพื่อความสมบูรณ์คนที่ควรจะกล่าวถึงคุณสมบัติหลัก Javascript ของมรดกกับห่วงโซ่ต้นแบบ บางอย่างเช่นนี้แสดงให้เห็นถึงความคิด:

RegExp.prototype.append = function(re) {
  return new RegExp(this.source + re.source, this.flags);
};

let regex = /[a-z]/g
.append(/[A-Z]/)
.append(/[0-9]/);

console.log(regex); //=> /[a-z][A-Z][0-9]/g


นี่คือคำตอบที่ดีที่สุดที่นี่
parttimeturtle

6

ขอบคุณโลกมหัศจรรย์แห่งเทมเพลตตัวอักษรตอนนี้คุณสามารถเขียนใหญ่หลายบรรทัดแสดงความคิดเห็นดีและแม้กระทั่ง regexes ซ้อนกันเชิงความหมายใน ES6

//build regexes without worrying about
// - double-backslashing
// - adding whitespace for readability
// - adding in comments
let clean = (piece) => (piece
    .replace(/((^|\n)(?:[^\/\\]|\/[^*\/]|\\.)*?)\s*\/\*(?:[^*]|\*[^\/])*(\*\/|)/g, '$1')
    .replace(/((^|\n)(?:[^\/\\]|\/[^\/]|\\.)*?)\s*\/\/[^\n]*/g, '$1')
    .replace(/\n\s*/g, '')
);
window.regex = ({raw}, ...interpolations) => (
    new RegExp(interpolations.reduce(
        (regex, insert, index) => (regex + insert + clean(raw[index + 1])),
        clean(raw[0])
    ))
);

การใช้สิ่งนี้คุณสามารถเขียน regexes ดังนี้:

let re = regex`I'm a special regex{3} //with a comment!`;

เอาท์พุท

/I'm a special regex{3}/

หรือ multiline เกี่ยวกับอะไร?

'123hello'
    .match(regex`
        //so this is a regex

        //here I am matching some numbers
        (\d+)

        //Oh! See how I didn't need to double backslash that \d?
        ([a-z]{1,3}) /*note to self, this is group #2*/
    `)
    [2]

เอาท์พุhelทเรียบร้อย!
"ถ้าฉันต้องการค้นหาบรรทัดใหม่จริง ๆ " แล้วใช้\nโง่!
ทำงานกับ Firefox และ Chrome ของฉัน


โอเค "สิ่งที่ซับซ้อนกว่านี้อีกเล็กน้อย"
แน่นอนนี่เป็นชิ้นส่วนของการทำลายวัตถุ JS parser ที่ฉันกำลังทำอยู่ :

regex`^\s*
    (
        //closing the object
        (\})|

        //starting from open or comma you can...
        (?:[,{]\s*)(?:
            //have a rest operator
            (\.\.\.)
            |
            //have a property key
            (
                //a non-negative integer
                \b\d+\b
                |
                //any unencapsulated string of the following
                \b[A-Za-z$_][\w$]*\b
                |
                //a quoted string
                //this is #5!
                ("|')(?:
                    //that contains any non-escape, non-quote character
                    (?!\5|\\).
                    |
                    //or any escape sequence
                    (?:\\.)
                //finished by the quote
                )*\5
            )
            //after a property key, we can go inside
            \s*(:|)
      |
      \s*(?={)
        )
    )
    ((?:
        //after closing we expect either
        // - the parent's comma/close,
        // - or the end of the string
        \s*(?:[,}\]=]|$)
        |
        //after the rest operator we expect the close
        \s*\}
        |
        //after diving into a key we expect that object to open
        \s*[{[:]
        |
        //otherwise we saw only a key, we now expect a comma or close
        \s*[,}{]
    ).*)
$`

มันออกมา /^\s*((\})|(?:[,{]\s*)(?:(\.\.\.)|(\b\d+\b|\b[A-Za-z$_][\w$]*\b|("|')(?:(?!\5|\\).|(?:\\.))*\5)\s*(:|)|\s*(?={)))((?:\s*(?:[,}\]=]|$)|\s*\}|\s*[{[:]|\s*[,}{]).*)$/

และใช้มันด้วยการสาธิตเล็ก ๆ น้อย ๆ ?

let input = '{why, hello, there, "you   huge \\"", 17, {big,smelly}}';
for (
    let parsed;
    parsed = input.match(r);
    input = parsed[parsed.length - 1]
) console.log(parsed[1]);

ส่งออกสำเร็จ

{why
, hello
, there
, "you   huge \""
, 17
,
{big
,smelly
}
}

สังเกตการจับสำเร็จของสตริงที่ยกมา
ฉันทดสอบมันบน Chrome และ Firefox ทำงานได้ดี!

ถ้าอยากรู้อยากเห็นคุณสามารถเช็คเอาสิ่งที่ผมทำและการสาธิต
แม้ว่ามันจะใช้งานได้กับ Chrome เท่านั้น แต่ Firefox ไม่รองรับการตอบกลับหรือกลุ่มที่มีชื่อ ดังนั้นโปรดสังเกตตัวอย่างที่ให้ไว้ในคำตอบนี้จริงๆแล้วเป็นรุ่น neutered และอาจถูกหลอกได้ง่ายในการยอมรับสตริงที่ไม่ถูกต้อง


1
คุณควรนึกถึงการส่งออกสิ่งนี้เป็นแพ็คเกจ NodeJS มันยอดเยี่ยมมาก
rmobis

1
ถึงแม้ว่าผมจะไม่เคยทำมันเองมีการกวดวิชาอย่างละเอียดสวยที่นี่: zellwk.com/blog/publish-to-npm ฉันขอแนะนำให้ตรวจสอบ np ที่ส่วนท้ายของหน้า ฉันไม่เคยใช้มัน แต่ Sindre Sorhus เป็นผู้วิเศษกับสิ่งเหล่านี้ดังนั้นฉันจะไม่ผ่านมันไป
rmobis

4

regex ด้านบนขาดเครื่องหมายทับสีดำบางอันซึ่งทำงานไม่ถูกต้อง ดังนั้นฉันจึงแก้ไข regex โปรดพิจารณา regex นี้ที่ใช้งานได้ 99.99% สำหรับการตรวจสอบอีเมล

let EMAIL_REGEXP = 
new RegExp (['^(([^<>()[\\]\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\.,;:\\s@\"]+)*)',
                    '|(".+"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.',
                    '[0-9]{1,3}\])|(([a-zA-Z\\-0-9]+\\.)+',
                    '[a-zA-Z]{2,}))$'].join(''));

1

เพื่อหลีกเลี่ยงอาร์เรย์joinคุณยังสามารถใช้ไวยากรณ์ต่อไปนี้:

var pattern = new RegExp('^(([^<>()[\]\\.,;:\s@\"]+' +
  '(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@' +
  '((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|' +
  '(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$');

0

โดยส่วนตัวแล้วฉันจะใช้ regex ที่ซับซ้อนน้อยกว่า:

/\S+@\S+\.\S+/

แน่นอนว่ามันแม่นยำน้อยกว่ารูปแบบปัจจุบันของคุณ แต่คุณพยายามทำอะไรให้สำเร็จ คุณพยายามที่จะตรวจจับข้อผิดพลาดที่ไม่ตั้งใจจากที่ผู้ใช้ของคุณอาจป้อนหรือคุณกังวลว่าผู้ใช้ของคุณอาจพยายามป้อนที่อยู่ที่ไม่ถูกต้องหรือไม่? ถ้าเป็นครั้งแรกฉันจะไปหารูปแบบที่ง่ายขึ้น หากเป็นตัวหลังการยืนยันโดยการตอบกลับอีเมลที่ส่งไปยังที่อยู่นั้นอาจเป็นตัวเลือกที่ดีกว่า

อย่างไรก็ตามหากคุณต้องการใช้รูปแบบปัจจุบันของคุณจะเป็นการง่ายกว่าที่จะอ่าน (และบำรุงรักษา!) โดยสร้างจากรูปแบบย่อยที่มีขนาดเล็กลงเช่นนี้

var box1 = "([^<>()[\]\\\\.,;:\s@\"]+(\\.[^<>()[\\]\\\\.,;:\s@\"]+)*)";
var box2 = "(\".+\")";

var host1 = "(\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])";
var host2 = "(([a-zA-Z\-0-9]+\\.)+[a-zA-Z]{2,})";

var regex = new RegExp("^(" + box1 + "|" + box2 + ")@(" + host1 + "|" + host2 + ")$");

21
Downvoting - แม้ว่าความคิดเห็นของคุณเกี่ยวกับการลดความซับซ้อนของ regex นั้นถูกต้องแล้ว OP จะถามวิธีการ "แยก regex ยาวหลายบรรทัด" ดังนั้นแม้ว่าคำแนะนำของคุณจะถูกต้อง แต่ก็มีการให้ด้วยเหตุผลที่ผิด เช่นการเปลี่ยนตรรกะทางธุรกิจเพื่อหลีกเลี่ยงภาษาการเขียนโปรแกรม นอกจากนี้ตัวอย่างรหัสที่คุณให้นั้นค่อนข้างน่าเกลียด
sleepycal

4
@sleepycal ฉันคิดว่า Bart ได้ตอบคำถามแล้ว ดูหัวข้อสุดท้ายของคำตอบของเขา เขาได้ตอบคำถามและให้ทางเลือกอื่น
Nidhin David

0

คุณสามารถใช้การดำเนินการกับสตริง

var pattenString = "^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|"+
"(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|"+
"(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$";
var patten = new RegExp(pattenString);

0

ฉันพยายามปรับปรุงคำตอบของโครันด้วยการห่อหุ้มทุกอย่างและนำการสนับสนุนมาแบ่งกลุ่มจับและชุดตัวละครทำให้วิธีนี้มีความหลากหลายมากขึ้น

ในการใช้ตัวอย่างนี้คุณต้องเรียกใช้ฟังก์ชัน Variadic combineRegexซึ่งอาร์กิวเมนต์เป็นวัตถุนิพจน์ทั่วไปที่คุณต้องรวม การใช้งานสามารถพบได้ที่ด้านล่าง

ไม่สามารถแยกกลุ่มการจับได้โดยตรงด้วยวิธีนี้เนื่องจากจะปล่อยบางส่วนไว้ในวงเล็บเพียงอันเดียว เบราว์เซอร์ของคุณจะล้มเหลวโดยมีข้อยกเว้น

แต่ฉันแค่ส่งเนื้อหาของกลุ่มการดักจับภายในอาเรย์ วงเล็บจะถูกเพิ่มโดยอัตโนมัติเมื่อcombineRegexพบอาร์เรย์

ยิ่งไปกว่านั้นปริมาณปริมาณจำเป็นต้องทำตาม ถ้าด้วยเหตุผลบางอย่างนิพจน์ทั่วไปจะต้องถูกแยกต่อหน้าตัวนับคุณจำเป็นต้องเพิ่มวงเล็บคู่หนึ่ง สิ่งเหล่านี้จะถูกลบโดยอัตโนมัติ ประเด็นก็คือกลุ่มจับภาพที่ว่างเปล่านั้นไร้ประโยชน์เลยทีเดียวและด้วยวิธีนี้ตัววัดปริมาณก็มีบางสิ่งที่จะอ้างอิง วิธีการเดียวกันสามารถใช้กับสิ่งต่าง ๆ เช่นกลุ่มที่ไม่ถูกดักจับ ( /(?:abc)/กลายเป็น[/()?:abc/])

นี่คือคำอธิบายที่ดีที่สุดโดยใช้ตัวอย่างง่ายๆ:

var regex = /abcd(efghi)+jkl/;

จะกลายเป็น:

var regex = combineRegex(
    /ab/,
    /cd/,
    [
        /ef/,
        /ghi/
    ],
    /()+jkl/    // Note the added '()' in front of '+'
);

หากคุณต้องแยกชุดอักขระคุณสามารถใช้อ็อบเจกต์ ( {"":[regex1, regex2, ...]}) แทนอาร์เรย์ ( [regex1, regex2, ...]) เนื้อหาของคีย์สามารถเป็นอะไรก็ได้ตราบเท่าที่วัตถุมีเพียงหนึ่งคีย์ โปรดทราบว่าแทนที่จะ()ต้องใช้]เป็นตัวจำลองเริ่มต้นหากตัวอักษรตัวแรกสามารถตีความได้ว่าเป็นตัวบอกปริมาณ เช่น/[+?]/กลายเป็น{"":[/]+?/]}

นี่คือตัวอย่างและเป็นตัวอย่างที่สมบูรณ์มากขึ้น:

function combineRegexStr(dummy, ...regex)
{
    return regex.map(r => {
        if(Array.isArray(r))
            return "("+combineRegexStr(dummy, ...r).replace(dummy, "")+")";
        else if(Object.getPrototypeOf(r) === Object.getPrototypeOf({}))
            return "["+combineRegexStr(/^\]/, ...(Object.entries(r)[0][1]))+"]";
        else 
            return r.source.replace(dummy, "");
    }).join("");
}
function combineRegex(...regex)
{
    return new RegExp(combineRegexStr(/^\(\)/, ...regex));
}

//Usage:
//Original:
console.log(/abcd(?:ef[+A-Z0-9]gh)+$/.source);
//Same as:
console.log(
  combineRegex(
    /ab/,
    /cd/,
    [
      /()?:ef/,
      {"": [/]+A-Z/, /0-9/]},
      /gh/
    ],
    /()+$/
  ).source
);


0

@ คำตอบที่ยอดเยี่ยมของ Hashbrown ทำให้ฉันมาถูกทางแล้ว นี่คือเวอร์ชันของฉันซึ่งได้รับแรงบันดาลใจจากบล็อกนี้ด้วย

function regexp(...args) {
  function cleanup(string) {
    // remove whitespace, single and multi-line comments
    return string.replace(/\s+|\/\/.*|\/\*[\s\S]*?\*\//g, '');
  }

  function escape(string) {
    // escape regular expression
    return string.replace(/[-.*+?^${}()|[\]\\]/g, '\\$&');
  }

  function create(flags, strings, ...values) {
    let pattern = '';
    for (let i = 0; i < values.length; ++i) {
      pattern += cleanup(strings.raw[i]);  // strings are cleaned up
      pattern += escape(values[i]);        // values are escaped
    }
    pattern += cleanup(strings.raw[values.length]);
    return RegExp(pattern, flags);
  }

  if (Array.isArray(args[0])) {
    // used as a template tag (no flags)
    return create('', ...args);
  }

  // used as a function (with flags)
  return create.bind(void 0, args[0]);
}

ใช้แบบนี้:

regexp('i')`
  //so this is a regex

  //here I am matching some numbers
  (\d+)

  //Oh! See how I didn't need to double backslash that \d?
  ([a-z]{1,3}) /*note to self, this is group #2*/
`

ในการสร้างRegExpวัตถุนี้:

/(\d+)([a-z]{1,3})/i
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.