ทำไมช่วง [01-12] ไม่ทำงานตามที่คาดไว้


93

ฉันพยายามใช้รูปแบบช่วง[01-12]ใน regex เพื่อจับคู่ mm สองหลัก แต่ไม่ได้ผลตามที่คาดไว้


9
คุณกำลังจับคู่ตัวอักษรไม่ลำดับตัวอักษร โดยทั่วไปคุณจะจับคู่กับ 0, 1 ถึง 1 และ 2 (เช่น 0, 1 และ 2) พิจารณาสิ่งนี้: [a-z0-9]สิ่งนี้จะจับคู่ตัวอักษรตัวพิมพ์เล็กและตัวเลขทั้งหมด แต่เป็นเพียงอักขระตัวเดียว
Lasse V.Karlsen

fwiw ฉันสร้างเครื่องมือ javascript ที่สร้าง regex ที่ได้รับการปรับให้เหมาะสมที่สุดจากสองอินพุต (ต่ำสุด / สูงสุด) github.com/jonschlinkert/to-regex-range
jonschlinkert

0 [1-9] | 1 [0-2] -> 0 | 1 | 2 -> [] ใน regex แสดงถึงคลาสอักขระ หากไม่มีการระบุช่วงจะเป็นไปโดยปริยายหรือทุกอักขระ
Badri Gs

คุณต้องจับคู่กับนิพจน์ทั่วไปหรือไม่? หากไม่เป็นเช่นนั้นคุณสามารถ: 1. ) เพียงแค่ใช้\d+รูปแบบ 2. ) แปลงสตริงที่ตรงกันเป็นตัวเลขในรหัสของคุณ แล้ว 3. ) if(num >= 0 && num <= 12){ /*do something*/ }ตรวจสอบช่วงจำนวนเช่น เร็วและยืดหยุ่นมาก
acegs

คำตอบ:


199

ดูเหมือนคุณจะเข้าใจผิดว่านิยามคลาสอักขระทำงานอย่างไรใน regex

เพื่อให้ตรงกับใด ๆ ของสตริง01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11หรือ12บางอย่างเช่นงานนี้:

0[1-9]|1[0-2]

อ้างอิง


คำอธิบาย

คลาสอักขระโดยตัวมันเองจะพยายามจับคู่อักขระหนึ่งตัวจากสตริงอินพุต [01-12]จริงกำหนด[012]เป็นตัวละครคลาสที่ตรงกับตัวละครตัวหนึ่งจากการป้อนข้อมูลกับใด ๆ ของ 3 ตัวอักษร0, หรือ12

-นิยามช่วงไปจาก1การซึ่งรวมถึงเพียง1 1ในทางกลับกันบางอย่างเช่น[1-9]มี1, 2, 3, 4, 5, 6, 7, ,89

[this|that]มือใหม่มักจะทำให้ความผิดพลาดของการกำหนดสิ่งที่ต้องการ สิ่งนี้ไม่ "ได้ผล" นี้กำหนดคำนิยามของตัวละคร[this|a]คือมันตรงกับตัวละครตัวหนึ่งจากการป้อนข้อมูลใด ๆ กับ 6 ตัวอักษรในt, h, i, s, หรือ| aมากกว่าที่จะ(this|that)เป็นไปได้คือสิ่งที่ตั้งใจไว้

อ้างอิง


วิธีกำหนดช่วง

ตอนนี้เห็นได้ชัดว่ารูปแบบที่เหมือนbetween [24-48] hoursไม่ได้ "ทำงาน" คลาสอักขระในกรณีนี้เทียบเท่ากับ[248].

นั่นคือ-ในนิยามคลาสอักขระไม่ได้กำหนดช่วงตัวเลขในรูปแบบ เอ็นจิ้น Regex ไม่ "เข้าใจ" ตัวเลขในรูปแบบจริงๆยกเว้นไวยากรณ์การทำซ้ำแบบ จำกัด (เช่นการa{3,5}จับคู่ระหว่าง 3 ถึง 5 a)

การกำหนดช่วงแทนใช้การเข้ารหัส ASCII / Unicode ของอักขระเพื่อกำหนดช่วง อักขระ0ถูกเข้ารหัสใน ASCII เป็นทศนิยม 48 9คือ 57 ดังนั้นนิยามอักขระจึง[0-9]รวมอักขระทั้งหมดที่มีค่าอยู่ระหว่างทศนิยม 48 ถึง 57 ในการเข้ารหัส ค่อนข้างสมเหตุสมผลโดยการออกแบบเหล่านี้เป็นตัวละคร0, 1, ... 9,

ดูสิ่งนี้ด้วย


อีกตัวอย่างหนึ่ง: A ถึง Z

มาดูนิยามคลาสอักขระทั่วไปอื่นกัน [a-zA-Z]

ใน ASCII:

  • A= 65, Z= 90
  • a= 97, z= 122

ซึ่งหมายความว่า:

  • [a-zA-Z]และ[A-Za-z]เทียบเท่า
  • ในรสชาติส่วนใหญ่[a-Z]มีแนวโน้มที่จะเป็นช่วงอักขระที่ผิดกฎหมาย
    • เนื่องจากa(97) "มากกว่า" มากกว่าZ(90)
  • [A-z] ถูกกฎหมาย แต่รวมถึงอักขระหกตัวเหล่านี้ด้วย:
    • [(91), \(92), ](93), ^(94), _(95), `(96)

คำถามที่เกี่ยวข้อง


สำหรับฉันฉันกำลังมองหาเดือนที่ไม่มีคำนำหน้าด้วย 0 ถ้าตัวเลขหลักเดียว และฉันใช้สิ่งนี้ ([1-9] | (1 [0-2])) และได้ผล
bunjeeb

3
สิ่งสำคัญที่ควรทราบ:หากคุณพบว่าหน้านี้ต้องการคำตอบสำหรับช่วงตัวเลขของคุณที่มีเพียงหลักเดียวก่อนถึงหลักสิบ0[1-9]|1[0-2]จะไม่ได้ผล เปลี่ยนไปขั้นตอนต่อไปตรรกะ[1-9]|1[0-2]ไม่ทำงานอย่างใดอย่างหนึ่งด้วยเหตุผลที่เข้าใจได้ (มันตรงกับ1เฉพาะใน10, 11และ12) ก็ต้องใช้\b(?:[0-9]|1[0-1])\bเพื่อป้องกันนั้น \bตรวจสอบให้แน่ใจว่า regex ตรงกับคำ (หรือในกรณีนี้) ขอบเขต ( ^& $ไม่ได้); วงเล็บทำให้หรือ ( |) พิจารณาอีกด้านหนึ่งของมัน และสุดท้าย?:คืออย่าสร้างชุดย่อยด้วยการใช้วงเล็บ
user66001

@polygenelubricants: "1,2,3,4,5,6,7,8,9,10,17,18".match(/^(([1-9]|1[0-7])\,?)+$/g )คุณช่วยบอกหน่อยได้ไหมว่าเหตุใด JS regex จึงตรงกับ 17?
edam

@edam - polygenelubricants สามารถและเพื่อให้สามารถฉัน แต่แล้วเราต้องการจะตอบquesti ... รอ ... นี่เป็นคำถามที่คุณจะถามในการแสดงความคิดเห็น ? มีrulezในไซต์นี้;) ถามคำถามหากคุณมีคำถามใหม่ ความคิดเห็นเป็นเพียงการวิพากษ์วิจารณ์และขอคำชี้แจงและสำหรับการตอบสนองต่อสิ่งเหล่านั้น
robinCTS

1
@edam โอ้ฉันเห็น คุณไม่อีกครั้งถามว่ามันเป็นคำถามหนึ่งชั่วโมงต่อมา เยี่ยมมาก! อย่างไรก็ตามอาจเป็นความคิดที่ดีที่จะลบความคิดเห็นของคุณที่นี่
robinCTS

24

คลาสอักขระในนิพจน์ทั่วไปแสดงโดย[...]ไวยากรณ์ระบุกฎเพื่อจับคู่อักขระเดี่ยวในอินพุต เป็นเช่นนี้ทุกสิ่งที่คุณเขียนระหว่างวงเล็บระบุว่าเพื่อให้ตรงกับตัวอักษรตัวเดียว

รูปแบบของคุณ[01-12]แบ่งออกเป็นดังนี้:

  • 0 - จับคู่เลขหลักเดียว 0
  • หรือ 1-1 จับคู่ตัวเลขหลักเดียวในช่วง 1 ถึง 1
  • หรือ 2 จับคู่เลขหลักเดียว 2

โดยพื้นฐานแล้วทั้งหมดที่คุณจับคู่คือ 0, 1 หรือ 2

ในการจับคู่ที่คุณต้องการการจับคู่ตัวเลขสองหลักตั้งแต่ 01-12 เป็นตัวเลขคุณต้องคิดว่าจะมีลักษณะเป็นข้อความอย่างไร

คุณมี:

  • 01-09 (เช่นหลักแรกคือ 0 หลักที่สองคือ 1-9)
  • 10-12 (เช่นหลักแรกคือ 1 หลักที่สองคือ 0-2)

จากนั้นคุณจะต้องเขียนนิพจน์ทั่วไปสำหรับสิ่งนั้นซึ่งอาจมีลักษณะดังนี้:

  +-- a 0 followed by 1-9
  |
  |      +-- a 1 followed by 0-2
  |      |
<-+--> <-+-->
0[1-9]|1[0-2]
      ^
      |
      +-- vertical bar, this roughly means "OR" in this context

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

ตัวอย่างเช่น[0-1][0-9]โดยทั่วไปรูปแบบจะตรงกับตัวเลข 00-19 ซึ่งมากกว่าที่คุณต้องการเล็กน้อย

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


9

สิ่งนี้ยังใช้งานได้:

^([1-9]|[0-1][0-2])$

[1-9] จับคู่ตัวเลขเดียวระหว่าง 1 ถึง 9

[0-1][0-2] จับคู่ตัวเลขสองหลักระหว่าง 10 ถึง 12

มีตัวอย่างดีๆอยู่ที่นี่


2
เพื่อให้ถูกต้อง[0-1][0-2]ตรงกัน00ด้วย ที่กล่าวว่า +1 สำหรับลิงก์ (ซึ่งฉันใช้ในคำตอบของฉัน)
polygenelubricants

2
[0-1][0-2]ต้องตีความอย่างระมัดระวังเนื่องจากจะช่วยให้สตริงชอบ00, 01และ02แต่ก็ไม่ยอมรับ03ถึง09ยอมรับในที่สุด10, และ11 12regex ที่ถูกต้องสำหรับสิ่งนั้นคือ[1-9]|1[0-2]หรือแม้กระทั่ง0*([1-9]|1[0-2])(สุดท้ายนี้อนุญาตให้มีเลขศูนย์นำหน้าจำนวนเท่าใดก็ได้)
Luis Colorado

1

[]ในนิพจน์ทั่วไปแสดงถึงตัวละครคลาส หากไม่มีการระบุช่วงจะเป็นไปโดยปริยายหรือ s ทุกอักขระที่อยู่ในนั้นรวมกัน ดังนั้นจึง[abcde]เหมือนกับ(a|b|c|d|e)ยกเว้นว่าจะไม่จับภาพอะไรเลย มันจะตรงกับคนใดคนหนึ่งของa, b, c, หรือd eทุกช่วงบ่งชี้ว่าเป็นชุดของตัวละคร ; [ac-eg]ระบุว่า "จับคู่aอักขระใดตัวหนึ่งของ: อักขระใดก็ได้ระหว่างcและeหรือg" ดังนั้นการจับคู่ของคุณบอกว่า "ตรงกับคนใดคนหนึ่งของ: 0; ตัวอักษรใด ๆ ระหว่าง1และ1( เช่นเพียง1) 2หรือ

เป้าหมายของคุณคือการระบุช่วงตัวเลข: ตัวเลขใด ๆ ที่อยู่ระหว่าง01และ12เขียนด้วยตัวเลขสองหลัก ในกรณีนี้โดยเฉพาะคุณสามารถจับคู่กับ0[1-9]|1[0-2]: อย่างใดอย่างหนึ่ง0ตามหลักใด ๆ ระหว่าง1และ9หรือ1ตามหลักใด ๆ ระหว่างและ0 2โดยทั่วไปคุณสามารถเปลี่ยนช่วงตัวเลขใด ๆ ให้เป็นนิพจน์ทั่วไปที่ถูกต้องในลักษณะที่คล้ายกัน อย่างไรก็ตามอาจมีตัวเลือกที่ดีกว่านิพจน์ทั่วไปหรือฟังก์ชันหรือโมดูลที่มีอยู่ซึ่งสามารถสร้างนิพจน์ทั่วไปให้คุณได้ ขึ้นอยู่กับภาษาของคุณ


0

ดังที่ polygenelubricants บอกว่าคุณจะมองหา 0 | 1-1 | 2 มากกว่าสิ่งที่คุณต้องการเนื่องจากคลาสของตัวละคร (สิ่งต่างๆใน []) จับคู่อักขระมากกว่าสตริง


3
0|1-1|2- สัญกรณ์นี้ทำให้เข้าใจผิดมาก สิ่งที่ต้องการ0|1|2จะถูกต้องมากขึ้น
polygenelubricants

0

ใช้สิ่งนี้:

0?[1-9]|1[012]
  • 07: ถูกต้อง
  • 7: ถูกต้อง
  • 0: ไม่ตรงกัน
  • 00: ไม่ตรงกัน
  • 13: ไม่ตรงกัน
  • 21: ไม่ตรงกัน

ในการทดสอบรูปแบบเมื่อ 07/2018 ให้ใช้สิ่งนี้:

/^(0?[1-9]|1[012])\/([2-9][0-9]{3})$/

(ช่วงวันที่ระหว่าง 01/2000 ถึง 12/9999)


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