การตั้งค่าสถานะหลายบรรทัดของ regex JavaScript ไม่ทำงาน


265

ฉันเขียน regex เพื่อดึงข้อมูลสตริงจาก HTML แต่ดูเหมือนว่าการตั้งค่าสถานะหลายบรรทัดไม่ทำงาน

นี่คือรูปแบบของฉันและฉันต้องการได้รับข้อความในh1แท็ก

var pattern= /<div class="box-content-5">.*<h1>([^<]+?)<\/h1>/mi
m = html.search(pattern);
return m[1];

ฉันสร้างสตริงเพื่อทดสอบ เมื่อสตริงมี "\ n" ผลลัพธ์จะเป็นโมฆะเสมอ ถ้าฉันลบ "\ n" ทั้งหมดมันให้ผลลัพธ์ที่ถูกต้องกับฉันไม่ว่าจะมีหรือไม่มี/mธง

เกิดอะไรขึ้นกับ regex ของฉัน


14
อย่าใช้นิพจน์ทั่วไปเพื่อแยก HTML, HTML ไม่ใช่ภาษาปกติ ใช้ HTML parser, resp DOM นั่นก็ง่ายกว่ามาก
Svante

คุณกำลังมองหา DOTALL ไม่ใช่ multiline
Vanuan

โปรดทราบว่า JavaScript จะมีdotAllตัวแก้ไขในไม่ช้าดังนั้นคุณจึงสามารถทำได้/.../sและจุดของคุณจะตรงกับบรรทัดใหม่ ตั้งแต่เดือนกรกฎาคม 2017 อยู่หลังธงใน Chrome

คำตอบ:


609

คุณกำลังมองหา/.../sตัวดัดแปลงหรือที่เรียกว่าตัวดัดแปลงdotall มันบังคับให้จุด.ให้ตรงกับบรรทัดใหม่ซึ่งมันไม่ได้ทำตามค่าเริ่มต้น

ข่าวร้ายก็คือว่ามันไม่ได้อยู่ใน JavaScript (มันไม่เหมือน ES2018, ดูด้านล่าง) ข่าวดีก็คือคุณสามารถหลีกเลี่ยงได้โดยใช้คลาสตัวละคร (เช่น\s) และการปฏิเสธ ( \S) ร่วมกันเช่นนี้:

[\s\S]

ดังนั้นในกรณีของคุณ regex จะกลายเป็น:

/<div class="box-content-5">[\s\S]*<h1>([^<]+?)<\/h1>/i

ในฐานะของ ES2018, JavaScript สนับสนุนs(dotAll) ธงดังนั้นในสภาพแวดล้อมที่ทันสมัยแสดงออกปกติของคุณอาจจะเป็นคุณเขียนมัน แต่ที่มีsธงที่สิ้นสุด (มากกว่าm; mการเปลี่ยนแปลงวิธีการ^และ$การทำงานไม่ได้.):

/<div class="box-content-5">.*<h1>([^<]+?)<\/h1>/is

5
@simo จับคู่อักขระช่องว่างหรืออักขระที่ไม่ใช่ช่องว่างจับคู่อักขระใด ๆ ได้อย่างมีประสิทธิภาพ มันเหมือน.แต่การจับคู่ช่องว่างด้วย ( \s) หมายถึงการจับคู่\n(ซึ่ง.ไม่ได้ทำใน JavaScript หรือสามารถทำกับsธง)
alex

1
คำตอบนี้ถูกเพิ่มไปยังคำถามที่พบบ่อยของสแต็คโอเวอร์โฟลว์นิพจน์ปกติภายใต้ "ตัวดัดแปลง"
aliteralmind

40
ตาม MDN [^]ยังทำงานเพื่อจับคู่อักขระใด ๆ รวมถึงบรรทัดใหม่ใน JavaScript ดูdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/
......

6
สำหรับปัญหาด้านประสิทธิภาพขอแนะนำให้ใช้ตัว*?วัดปริมาณแทน*เพื่อหลีกเลี่ยงความโลภ สิ่งนี้จะหลีกเลี่ยงการจับ<h1> สุดท้ายของเอกสาร: นั่นอาจไม่ใช่สิ่งที่คุณต้องการและไม่มีประสิทธิภาพเนื่องจาก regexp จะค้นหา <h1> ต่อไปจนถึงจุดสิ้นสุดของสตริงแม้ว่าจะเคยพบมาก่อนแล้วก็ตาม
KrisWebDev

9
เวอร์ชั่น [^] เป็นวิธีที่ง่ายขึ้นในคอมไพเลอร์ regexp และกระชับยิ่งขึ้น
Erik Corry

21

คุณต้องการsโมดิฟายเออร์ (dotall) ซึ่งดูเหมือนไม่มีอยู่ใน Javascript คุณสามารถแทนที่.ด้วย [\ s \ S] ตามที่แนะนำโดย @molf โมดิmฟายเออร์ (หลายบรรทัด) ทำให้ ^ และ $ ตรงกับสายแทนสตริงทั้งหมด


4
คุณอาจเพิ่มว่า / s "โมดิฟายเออร์ตั้งค่าโหมด singleline เมื่อเทียบกับโหมดหลาย
บรรทัด

เก้าปีต่อมา JavaScript ในขณะนี้มีการsตั้งค่าสถานะ (ES2018) :-)
TJ Crowder

12

[\s\S]ไม่ได้ผลสำหรับฉันใน nodejs 6.11.3 จากเอกสาร RegExpมันบอกว่าจะใช้[^]งานได้สำหรับฉัน

(จุด, จุดทศนิยม) จับคู่อักขระเดี่ยวใด ๆ ยกเว้นตัววางสาย: \ n, \ r, \ u2028 หรือ \ u2029

ภายในชุดอักขระจุดสูญเสียความหมายพิเศษและตรงกับจุดตัวอักษร

โปรดทราบว่าการตั้งค่าสถานะ m multiline ไม่ได้เปลี่ยนพฤติกรรมของจุด ดังนั้นในการจับคู่รูปแบบข้ามหลายบรรทัดสามารถใช้ชุดอักขระ [^] (หากคุณไม่ได้หมายถึง IE เวอร์ชันเก่า) มันจะจับคู่อักขระใด ๆ รวมถึงบรรทัดใหม่

ตัวอย่างเช่น:

/This is on line 1[^]*?This is on line 3/m

ที่ไหน *? คือการคว้าแบบไม่โลภของ [0] หรือเกิดขึ้นอีก [^]


1
สำหรับผู้ที่สงสัยว่าสิ่งที่[^]หมายความว่ามันเป็นเหมือนคู่ปฏิเสธ: "ตรงกับตัวอักษรใด ๆ ที่เป็นไม่ได้ในเรื่องนี้ว่างรายการ"และดังนั้นจึงลงมาเพื่อบอกว่า"ตรงกับตัวอักษรใด ๆ"
trincot


0

คำแนะนำของฉันคือการดีกว่าที่จะแยกสตริงหลายบรรทัดด้วย "\ n" และเชื่อมต่อการแยกสตริงเดิมและกลายเป็นบรรทัดเดียวและง่ายต่อการจัดการ

<textarea class="form-control" name="Body" rows="12" data-rule="required" 
                  title='@("Your feedback ".Label())'
                  placeholder='@("Your Feedback here!".Label())' data-val-required='@("Feedback is required".Label())'
                  pattern="^[0-9a-zA-Z ,;/?.\s_-]{3,600}$" data-val="true" required></textarea>


$( document ).ready( function() {
  var errorMessage = "Please match the requested format.";
  var firstVisit = false;

  $( this ).find( "textarea" ).on( "input change propertychange", function() {

    var pattern = $(this).attr( "pattern" );
    var element = $( this );

    if(typeof pattern !== typeof undefined && pattern !== false)
    {
      var ptr = pattern.replace(/^\^|\$$/g, '');
      var patternRegex = new RegExp('^' + pattern.replace(/^\^|\$$/g, '') + '$', 'gm');     

      var ks = "";
      $.each($( this ).val().split("\n"), function( index, value ){
        console.log(index + "-" + value);
        ks += " " + value;
      });      
      //console.log(ks);

      hasError = !ks.match( patternRegex );
      //debugger;

      if ( typeof this.setCustomValidity === "function") 
      {
        this.setCustomValidity( hasError ? errorMessage : "" );
      } 
      else 
      {
        $( this ).toggleClass( "invalid", !!hasError );
        $( this ).toggleClass( "valid", !hasError );

        if ( hasError ) 
        {
          $( this ).attr( "title", errorMessage );
        } 
        else
        {
          $( this ).removeAttr( "title" );
        }
      }
    }

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