ต้องใช้อักขระพิเศษใดในการแสดงออกปกติ


389

ฉันเบื่อที่จะพยายามเดาอยู่เสมอว่าถ้าฉันควรหลีกเลี่ยงอักขระพิเศษเช่น ' ()[]{}|' ฯลฯ เมื่อใช้งาน regexps จำนวนมาก

มันแตกต่างกับตัวอย่างเช่น Python, sed, grep, awk, Perl, เปลี่ยนชื่อ, Apache, find และอื่น ๆ มีกฎชุดใดบ้างที่บอกเวลาที่ฉันควรและเมื่อใดที่ฉันไม่ควรหลีกเลี่ยงอักขระพิเศษ? มันขึ้นอยู่กับประเภท regexp เช่น PCRE, POSIX หรือ regexps เพิ่มเติมหรือไม่


4
ไลบรารี regex ที่ดีมีฟังก์ชันเช่น " escape()" เพื่ออนุญาตให้ใช้สตริงที่กำหนดเองเป็นส่วน regex
ivan_pozdeev

2
คุณสามารถใช้เครื่องมือตรวจสอบนิพจน์ Regex ออนไลน์เช่นgskinner.com/RegExr (ฟรี) (พิมพ์เมาส์แล้วเลื่อนเมาส์ไป regex ที่คุณพิมพ์ใน)
hexicle

2
ยกเว้นอักขระที่ไม่ใช่ตัวอักษรและตัวเลขทั้งหมด ระยะเวลา
Salman von Abbas

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

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

คำตอบ:


365

ตัวละครตัวไหนที่คุณต้องและไม่ต้องหลบหนีแน่นอนขึ้นอยู่กับรสชาติของ regex ที่คุณใช้งาน

สำหรับ PCRE และรสชาติที่เข้ากันได้กับ Perl อื่น ๆ ส่วนใหญ่ให้หลีกหนีคลาสอักขระภายนอกเหล่านี้:

.^$*+?()[{\|

และคลาสตัวละครเหล่านี้ภายใน:

^-]\

สำหรับ POSIX แบบขยาย regexes (ERE) ให้หลีกเลี่ยงคลาสอักขระภายนอกเหล่านี้ (เหมือนกับ PCRE):

.^$*+?()[{\|

การหลบหนีอักขระอื่น ๆ เป็นข้อผิดพลาดกับ POSIX ERE

ภายในคลาสอักขระแบ็กสแลชเป็นอักขระตามตัวอักษรในนิพจน์ปกติ POSIX คุณไม่สามารถใช้มันเพื่อหลบหนีอะไรก็ได้ คุณต้องใช้ "การจัดตำแหน่งอย่างชาญฉลาด" ถ้าคุณต้องการที่จะรวม metacharacters คลาสตัวละครเป็นตัวอักษร ใส่ ^ ที่ใดก็ได้ยกเว้นที่จุดเริ่มต้น,] ที่จุดเริ่มต้นและ - ที่จุดเริ่มต้นหรือจุดสิ้นสุดของคลาสตัวละครเพื่อจับคู่เหล่านี้อย่างแท้จริงเช่น:

[]^-]

ใน POSIX นิพจน์ปกติพื้นฐาน (BRE) นี่คือเมตาอักขระที่คุณต้องการหลีกเลี่ยงเพื่อระงับความหมาย:

.^$*[\

การหลีกเลี่ยงวงเล็บและวงเล็บปีกกาใน BREs ทำให้พวกเขามีความหมายพิเศษว่าเวอร์ชันที่ไม่ได้ใช้ค่า Escape มีใน EREs การใช้งานบางอย่าง (เช่น GNU) ยังให้ความหมายพิเศษกับตัวละครอื่นเมื่อหนีเช่น \? และ + การหลีกเลี่ยงอักขระอื่นนอกเหนือจาก ^ $ * () {} เป็นข้อผิดพลาดกับ BREs

ภายในคลาสอักขระ BREs ปฏิบัติตามกฎเดียวกันกับ ERE

หากทั้งหมดนี้ทำให้สปินหัวของคุณคว้าสำเนาของRegexBuddy บนแท็บสร้างคลิกแทรกโทเค็นแล้วตามตัวอักษร RegexBuddy จะเพิ่มทางหนีตามที่ต้องการ


1
ดูเหมือนว่าคุณจะลืม "/" ซึ่งต้องหนีออกนอกชั้นเรียนด้วย
jackthehipster

11
/ไม่ใช่ metacharacter ในรสชาตินิพจน์ทั่วไปใด ๆ ที่ฉันพูดถึงดังนั้นไวยากรณ์นิพจน์ทั่วไปไม่จำเป็นต้องหลบหนี เมื่อนิพจน์ทั่วไปถูกยกมาเป็นตัวอักษรในภาษาการเขียนโปรแกรมดังนั้นกฎการจัดรูปแบบสตริงหรือ regex ของภาษานั้นอาจต้องการ/หรือ"หรือ'จะหนีออกมาและอาจต้องใช้ `` `ที่จะหลบหนีทวีคูณ
Jan Goyvaerts

2
แล้วลำไส้ใหญ่ ":" มันจะต้องถูกหลบหนีในชั้นเรียนของตัวละครทั้งภายนอกหรือไม่ en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressionsกล่าวว่า "PCRE มีกฎการหลบหนีที่สอดคล้องกัน: อักขระที่ไม่ใช่ตัวอักษรและตัวเลขใด ๆ อาจถูกหลบหนีไปยังค่าเฉลี่ยของตัวอักษร [... ]"
nicolallias

4
MAY ที่จะหนีออกมาจะไม่เหมือนกับที่ควรจะหนีไป ไวยากรณ์ PCRE ไม่จำเป็นต้องใช้เครื่องหมายโคลอนแบบตัวอักษรดังนั้นการใช้เครื่องหมายโคลอนแบบตัวอักษรจะทำให้การอ่าน regex ของคุณยากขึ้น
Jan Goyvaerts

1
สำหรับ non-POSIX ERE (อันที่ฉันใช้บ่อยที่สุดเพราะมันคือสิ่งที่ Tcl นำไปใช้) การหลีกเลี่ยงสิ่งอื่น ๆ ไม่ได้สร้างข้อผิดพลาด
slebetman

61

Modern RegEx Flavours (PCRE)

รวมถึง C, C ++, Delphi, EditPad, Java, JavaScript, Perl, PHP (preg), PostgreSQL, PowerGREP, PowerShell, Python, REALbasic, Real Studio, ทับทิม, TCL, VB.Net, VBScript, wxWidgets, XML Schema, Xojo, XRegExp
ความเข้ากันได้ของ PCRE อาจแตกต่างกันไป

    ผู้แต่ง: . ^ $ * + - ? ( ) [ ] { } \ |


Legacy RegEx Flavors (BRE / ERE)

รวมถึง awk, ed, egrep, emacs, GNUlib, grep, PHP (ereg), MySQL, Oracle, R, sed
รองรับ PCRE อาจเปิดใช้งานในรุ่นที่ใหม่กว่าหรือโดยใช้ส่วนขยาย

ERE / awk / egrep / emacs

    นอกคลาสอักขระ: . ^ $ * + ? ( ) [ { } \ |
    ภายในคลาสอักขระ:^ - [ ]

BRE / เอ็ด / grep / sed

    นอกคลาสตัวละคร: . ^ $ * [ \
    ภายในคลาสอักขระ: ^ - [ ]
    สำหรับตัวอักษรอย่าหลบหนี: + ? ( ) { } |
    สำหรับพฤติกรรม regex มาตรฐาน Escape:\+ \? \( \) \{ \} \|


หมายเหตุ

  • หากไม่แน่ใจเกี่ยวกับตัวละครเฉพาะสามารถหลบหนีได้เช่น \xFF
  • อักขระตัวอักษรผสมตัวเลขไม่สามารถหลีกเลี่ยงได้ด้วยแบ็กสแลช
  • สัญลักษณ์ตามอำเภอใจสามารถหลบหนีด้วยแบ็กสแลชใน PCRE แต่ไม่สามารถใช้ BRE / ERE ได้ สำหรับ PCRE ] -จำเป็นต้องหลบหนีภายในคลาสตัวละครเท่านั้น แต่ฉันเก็บไว้ในรายการเดียวเพื่อความเรียบง่าย
  • สตริงนิพจน์ที่อ้างถึงจะต้องมีอักขระเครื่องหมายคำพูดล้อมรอบหนีและบ่อยครั้งที่เครื่องหมายแบ็กสแลชเพิ่มเป็นสองเท่า (เช่น"(\")(/)(\\.)"เมื่อเทียบกับ/(")(\/)(\.)/JavaScript)
  • นอกเหนือจากการหลบหนีการใช้งาน regex ที่แตกต่างกันอาจรองรับตัวดัดแปลงที่แตกต่างกันคลาสของตัวอักษรจุดยึดปริมาณและคุณสมบัติอื่น ๆ สำหรับรายละเอียดเพิ่มเติมตรวจสอบregular-expressions.infoหรือใช้regex101.comเพื่อทดสอบการแสดงออกของคุณมีชีวิตอยู่

1
มีข้อผิดพลาดมากมายในคำตอบของคุณซึ่งรวมถึง แต่ไม่ จำกัด เพียง: ไม่มีรสชาติ "ทันสมัย" ของคุณที่ต้องการ-หรือ]หลบหนีนอกคลาสอักขระ POSIX (BRE / ERE) ไม่มีตัวอักษรยกเว้นในชั้นเรียนของตัวละคร รสชาติของ regex ใน RTL ของ Delphi นั้นมาจาก PCRE Python, Ruby และ XML มีรสชาติของตัวเองที่ใกล้เคียงกับ PCRE มากกว่ารสชาติ POSIX
Jan Goyvaerts

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

22

น่าเสียดายที่มีชุดรหัสหลบหนีไม่ได้เพราะมันแตกต่างกันไปตามภาษาที่คุณใช้

อย่างไรก็ตามการรักษาหน้าเช่นหน้าเครื่องมือนิพจน์ปกติหรือสูตรโกงนิพจน์ปกตินี้อาจช่วยให้คุณสามารถกรองสิ่งต่าง ๆ ได้อย่างรวดเร็ว


1
ชีท Addbytes มีการผิดเพี้ยนไปอย่างมากและมีข้อผิดพลาดบางอย่าง ตัวอย่างเช่นมันบอกว่า\<และ\>เป็นขอบเขตของคำซึ่งเป็นความจริงเท่านั้น (AFAIK) ในไลบรารี Boost regex แต่ที่อื่นมันบอกว่า<และ>เป็น metacharacters และจะต้องหลบหนี (ไป\<และ\>) เพื่อให้ตรงกับพวกเขาอย่างแท้จริงซึ่งไม่เป็นความจริงในทุกรสชาติ
Alan Moore

5

น่าเสียดายที่ความหมายของสิ่งต่าง ๆ เช่น (และ \ (สลับกันระหว่างการแสดงออกปกติของสไตล์ Emacs และสไตล์อื่น ๆ ส่วนใหญ่) ดังนั้นหากคุณพยายามหลีกเลี่ยงสิ่งเหล่านี้คุณอาจทำสิ่งที่ตรงกันข้ามกับสิ่งที่คุณต้องการ

ดังนั้นคุณต้องรู้ว่าคุณกำลังพยายามอ้างถึงสไตล์แบบใด


5

POSIX รู้จักการเปลี่ยนแปลงหลายอย่างในนิพจน์ทั่วไป - นิพจน์ทั่วไปพื้นฐาน (BRE) และนิพจน์ทั่วไปที่ขยายเพิ่ม (ERE) และถึงอย่างนั้นก็ยังมีนิสัยใจคอเนื่องจากการใช้งานทางประวัติศาสตร์ของสาธารณูปโภคที่เป็นมาตรฐานโดย POSIX

ไม่มีกฎง่ายๆว่าเมื่อใดที่จะใช้สัญลักษณ์ใด ๆ หรือแม้กระทั่งสัญลักษณ์ที่คำสั่งที่กำหนดใช้

ลองอ่านหนังสือนิพจน์ปกติของ Jeff Friedl


4

จริง ๆ แล้วไม่มี มีซินเท็กซ์ regex ต่างกันประมาณครึ่งล้าน ดูเหมือนว่าพวกเขาจะลงมาที่ Perl, EMACS / GNU และ AT&T โดยทั่วไป แต่ฉันก็รู้สึกประหลาดใจเช่นกัน


4

บางครั้งการหลบหนีอย่างง่าย ๆ อาจเป็นไปไม่ได้สำหรับตัวละครที่คุณระบุไว้ ตัวอย่างเช่นการใช้แบ็กสแลชเพื่อหลีกเลี่ยงวงเล็บจะไม่ทำงานในด้านซ้ายมือของสตริงการแทนที่ใน sed คือ

sed -e 's/foo\(bar/something_else/'

ฉันมักจะใช้นิยามคลาสอักขระอย่างง่ายแทนดังนั้นนิพจน์ด้านบนจะกลายเป็น

sed -e 's/foo[(]bar/something_else/'

ที่ฉันค้นหางานสำหรับการใช้งาน regexp ส่วนใหญ่

คลาส BTW ตัวละครเป็นส่วนประกอบที่ดีของ vanilla regexp ดังนั้นพวกมันจึงมักจะทำงานในสถานการณ์ส่วนใหญ่ที่คุณต้องการหลบหนีจากตัวละครใน regexps

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

คุณอาจต้องการดู "หนังสือลูกประกาย" หรือที่เรียกว่า Effective Perl ( sanitized ลิงก์ Amazon ) โดยเฉพาะบทในนิพจน์ทั่วไปเพื่อรับรู้ถึงความแตกต่างในประเภทการประเมินของเครื่องยนต์ regexp

ไม่ใช่ทุกคนในโลก PCRE!

อย่างไรก็ตามเรื่องของ regexp นั้นค่อนข้างน่ากลัวเมื่อเทียบกับSNOBOL ! ตอนนี้ที่เป็นหลักสูตรการเขียนโปรแกรมที่น่าสนใจ! พร้อมกับหนึ่งบนSimula

ความสุขของการเรียนที่ UNSW ในช่วงปลายยุค 70! (-:


'sed' เป็นคำสั่งที่ชัดแจ้ง '(' ไม่พิเศษ แต่ '\ (' เป็นพิเศษ; ในทางตรงกันข้าม PCRE ย้อนความรู้สึกดังนั้น '(' เป็นพิเศษ แต่ '\ (' ไม่เป็นอย่างนี้) OP กำลังถามถึง
Jonathan Leffler

sed เป็นยูทิลิตี้ * nix ที่ใช้หนึ่งในชุดการประเมิน regexp ดั้งเดิมที่สุด PCRE ไม่เข้าสู่สถานการณ์ที่ฉันอธิบายเนื่องจากมันเกี่ยวข้องกับคลาส (ใน) ของออโตมาตา จำกัด (class) ที่แตกต่างกันพร้อมวิธีการประเมิน regexps ฉันคิดว่าคำแนะนำของฉันสำหรับชุดต่ำสุดของไวยากรณ์ regexp ยังคงมีอยู่
Rob Wells

1
บนระบบที่สอดคล้องกับ POSIX, sed ใช้ POSIX BRE ซึ่งฉันครอบคลุมในคำตอบของฉัน รุ่น GNU บนระบบ Linux ที่ทันสมัยใช้ POSIX BRE พร้อมกับส่วนขยายเล็กน้อย
Jan Goyvaerts

2

สำหรับ PHP "จะปลอดภัยเสมอที่จะนำหน้าตัวอักษรและตัวเลขที่ไม่ใช่" \ "เพื่อระบุว่าตัวย่อมาจากตัวมันเอง" - http://php.net/manual/en/regexp.reference.escape.php

ยกเว้นถ้าเป็น "หรือ": /

เพื่อหลีกเลี่ยงตัวแปรรูปแบบ regex (หรือตัวแปรบางส่วน) ใน PHP ใช้ preg_quote ()


2

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

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

แต่ละบริบทนี้กำหนดอักขระบางตัวด้วยฟังก์ชันการทำงานพิเศษ

เมื่อคุณต้องการส่งผ่านตัวอักษรอย่างแท้จริงโดยไม่ต้องใช้ฟังก์ชั่นพิเศษ (เฉพาะที่กับบริบท) นั่นคือกรณีที่คุณต้องหลบหนีสำหรับบริบทถัดไป ... ซึ่งอาจต้องใช้อักขระการหลบหนีอื่นซึ่งอาจจำเป็นต้องเพิ่มเติมด้วย หลบหนีในบริบทก่อนหน้า นอกจากนี้ยังมีสิ่งต่าง ๆ เช่นการเข้ารหัสตัวอักษร (ที่ร้ายกาจที่สุดคือ utf-8 เพราะดูเหมือนว่า ASCII สำหรับตัวละครทั่วไป แต่อาจถูกตีความทางเลือกแม้ว่าเทอร์มินัลจะขึ้นอยู่กับการตั้งค่าของมันดังนั้นมันอาจทำงานแตกต่างกัน / XML จำเป็นต้องเข้าใจกระบวนการอย่างถูกต้อง

เช่น regexp ในบรรทัดคำสั่งที่เริ่มต้นด้วยperl -npeจะต้องถ่ายโอนไปยังชุดของการเรียกระบบการเชื่อมต่อเป็นไพพ์ที่จัดการไฟล์แต่ละการเรียกระบบ exec นี้เพียงแค่มีรายการของข้อโต้แย้งที่คั่นด้วยช่องว่าง (ไม่หนี) และอาจจะเป็นท่อ (|) และการเปลี่ยนเส้นทาง (> N> N> & M) วงเล็บการขยายตัวของการโต้ตอบ*และ?,$(())... (ทั้งหมดนี้เป็นอักขระพิเศษที่ใช้โดย * sh ซึ่งอาจปรากฏขึ้นเพื่อแทรกแซงอักขระของนิพจน์ทั่วไปในบริบทถัดไป แต่จะถูกประเมินตามลำดับ: ก่อนบรรทัดคำสั่งบรรทัดคำสั่งถูกอ่านโดย โปรแกรมเป็น bash / sh / csh / tcsh / zsh ส่วนใหญ่อยู่ในเครื่องหมายคำพูดคู่หรือคำพูดเดียวการหลบหนีนั้นง่ายกว่า แต่ก็ไม่จำเป็นที่จะต้องพูดสตริงในบรรทัดคำสั่งเพราะพื้นที่ส่วนใหญ่จะต้องนำหน้าด้วยแบ็กสแลช ไม่จำเป็นต้องปล่อยให้มีฟังก์ชันขยายสำหรับอักขระ * และ? แต่สิ่งนี้แยกวิเคราะห์บริบทที่แตกต่างกันภายในเครื่องหมายคำพูดจากนั้นเมื่อบรรทัดคำสั่งถูกประเมิน regexp ที่ได้รับในหน่วยความจำ (ไม่ใช่เขียนในบรรทัดคำสั่ง) ได้รับการรักษาแบบเดียวกัน จะอยู่ในไฟล์ต้นฉบับสำหรับ regexp มีบริบทชุดอักขระภายในวงเล็บเหลี่ยม [],การแสดงออกปกติของ Perl สามารถยกมาได้โดยชุดอักขระที่ไม่ใช่ตัวเลขจำนวนมาก (เช่น m // // หรือ m: / better / for / path: ... )

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



0

สำหรับ Ionic (Typescript) คุณต้องทับสองครั้งเพื่อที่จะกวาดล้างตัวละคร ตัวอย่างเช่น (นี่คือเพื่อจับคู่อักขระพิเศษบางตัว):

"^(?=.*[\\]\\[!¡\'=ªº\\-\\_ç@#$%^&*(),;\\.?\":{}|<>\+\\/])"

ให้ความสนใจกับ] [ - _ . /ตัวละครตัวนี้ พวกเขาจะต้องถูกเฉือนสองครั้ง หากคุณไม่ทำเช่นนั้นคุณจะพบข้อผิดพลาดประเภทในรหัสของคุณ

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