ในบทความวิกิพีเดียนิพจน์ปกติมันก็ดูเหมือนว่า[[:digit:]]
= = [0-9]
\d
สถานการณ์อะไรบ้างที่พวกเขาไม่เท่ากัน? อะไรคือความแตกต่าง?
หลังจากการวิจัยบางอย่างฉันคิดว่าความแตกต่างอย่างหนึ่งคือการแสดงออกของวงเล็บปีกกา[:expr:]
ขึ้นอยู่กับสถานที่
ในบทความวิกิพีเดียนิพจน์ปกติมันก็ดูเหมือนว่า[[:digit:]]
= = [0-9]
\d
สถานการณ์อะไรบ้างที่พวกเขาไม่เท่ากัน? อะไรคือความแตกต่าง?
หลังจากการวิจัยบางอย่างฉันคิดว่าความแตกต่างอย่างหนึ่งคือการแสดงออกของวงเล็บปีกกา[:expr:]
ขึ้นอยู่กับสถานที่
คำตอบ:
ใช่มันคือ[[:digit:]]
~ [0-9]
~ \d
(โดยที่ ~ หมายถึง aproximate)
ในภาษาการเขียนโปรแกรมส่วนใหญ่ (ที่รองรับ) \d
≡ [[:digit:]]
(เหมือนกัน) น้อยกว่ากัน(ไม่อยู่ใน POSIX แต่มันอยู่ใน GNU )\d
[[:digit:]]
grep -P
มีตัวเลขจำนวนมากใน UNICODEตัวอย่างเช่น:
123456789 # Hindu-Arabic
เลขอารบิค
٠١٢٣٤٥٦٧٨٩ # ARABIC-INDIC
۰۱۲۳۴۵۶۷۸۹ # EXTENDED ARABIC-INDIC/PERSIAN
߀߁߂߃߄߅߆߇߈߉ # NKO DIGIT
०१२३४५६७८९ # DEVANAGARI
ซึ่งทั้งหมดอาจจะรวมอยู่ในหรือ[[:digit:]]
\d
แต่โดยทั่วไปเพียงตัวเลข[0-9]
ASCII0123456789
มีหลายภาษา: Perl, Java, Python, C. ซึ่ง[[:digit:]]
(และ\d
) เรียกร้องให้มีความหมายเพิ่มเติม ตัวอย่างเช่นรหัส perl นี้จะตรงกับตัวเลขทั้งหมดจากด้านบน:
$ a='0123456789 ٠١٢٣٤٥٦٧٨٩ ۰۱۲۳۴۵۶۷۸۹ ߀߁߂߃߄߅߆߇߈߉ ०१२३४५६७८९'
$ echo "$a" | perl -C -pe 's/[^\d]//g;' ; echo
0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८९
ซึ่งเทียบเท่ากับเลือกอักขระทั้งหมดที่มีคุณสมบัติ Unicode ของNumeric
และdigits
:
$ echo "$a" | perl -C -pe 's/[^\p{Nd}]//g;' ; echo
0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८९
grep ใดที่สามารถทำซ้ำได้ (เวอร์ชันเฉพาะของ pcre อาจมีรายการรหัสจุดตัวเลขภายใน Perl ที่แตกต่างกันกว่า Perl):
$ echo "$a" | grep -oP '\p{Nd}+'
0123456789
٠١٢٣٤٥٦٧٨٩
۰۱۲۳۴۵۶۷۸۹
߀߁߂߃߄߅߆߇߈߉
०१२३४५६७८९
เปลี่ยนเป็น [0-9] เพื่อดู:
$ echo "$a" | grep -o '[0-9]\+'
0123456789
สำหรับเฉพาะ POSIX BRE หรือ ERE: ไม่สนับสนุน (ไม่อยู่ใน POSIX แต่อยู่ใน GNU )
เป็นสิ่งจำเป็นโดย POSIX เพื่อให้สอดคล้องกับคลาสตัวละครหลักซึ่ง ISO C จำเป็นต้องเป็นอักขระตั้งแต่ 0 ถึง 9 และไม่มีอะไรอื่น ดังนั้นเพียงใน C สถานที่เกิดเหตุทั้งหมด, , และหมายถึงเหมือนกันว่า ไม่เคยมีใครตีความเป็นไปได้ที่มีอยู่ในระบบสาธารณูปโภคอื่น ๆ และมันก็เป็นเรื่องธรรมดาที่จะหมายถึงเฉพาะ รับการสนับสนุนจากสาธารณูปโภคไม่กี่\d
grep -P
[[:digit:]]
[0-9]
[0123456789]
\d
[[:digit:]]
[0123456789]
[[:digit:]]
[0123456789]
\d
สำหรับ[0-9]
ความหมายของการแสดงออกช่วงที่กำหนดโดย POSIX ในสถานที่ C; ในสถานที่อื่น ๆ มันอาจแตกต่างกัน (อาจเป็นคำสั่ง codepoint หรือคำสั่งการเปรียบเทียบหรืออย่างอื่น)
การใช้งานบางอย่างอาจเข้าใจช่วงที่แตกต่างจากลำดับ ASCII ธรรมดา (ตัวอย่างเช่น ksh93):
$ LC_ALL=en_US.utf8 ksh -c 'a="'"$a"'";echo "${a//[0-9]}"'
۹ ߀߁߂߃߄߅߆߇߈߉ ९
และนั่นคือแหล่งที่มาของข้อผิดพลาดที่รอให้เกิดขึ้น
iswctype()
และ BRE / ERE / ไวด์การ์ดในยูทิลิตี้ POSIX [0-9] และ [[: หลัก:]] จับคู่กับ 0123456789 เท่านั้น และจะมีการอธิบายอย่างชัดเจนในการแก้ไขมาตรฐานครั้งต่อไป
perl
ของ\d
ในโหมด Unicode ตรงกันบนตัวเลขทศนิยมจากสคริปต์อื่น ๆ ขอบคุณสำหรับสิ่งนั้น ด้วย PCRE ให้ดู(*UCP)
ใน GNU grep -Po '(*UCP)\d'
หรือgrep -Po '(*UCP)[[:digit:]]
คลาสที่ต้องยึดตามคุณสมบัติ Unicode
[:digit:]
ไวยากรณ์จะแนะนำให้คุณต้องการใช้การแปลเป็นสิ่งที่ผู้ใช้คิดว่าเป็นหลัก ฉันไม่เคยใช้[:digit:]
เพราะในทางปฏิบัติเหมือนกับ[0-9]
และในกรณีใด ๆ ฉันต้องการจับคู่กับ 0123456789 เสมอฉันไม่เคยตั้งใจจะจับคู่٠١٢٣٤٥٦٧٨٩
และฉันไม่สามารถนึกถึงกรณีการใช้งานที่ใคร ๆ ก็อยากเทียบเลขทศนิยม ในสคริปต์ใด ๆ ที่มีโปรแกรมอรรถประโยชน์ POSIX เห็นแล้วยังอภิปรายปัจจุบันเกี่ยวกับ[:blank:]
ใน zsh ML คลาสของตัวละครเหล่านั้นยุ่งเหยิงไปหน่อย
ขึ้นอยู่กับว่าคุณกำหนดตัวเลขอย่างไร [0-9]
มีแนวโน้มที่จะเป็นแค่ ASCII (หรืออาจเป็นอย่างอื่นที่ไม่ใช่ ASCII หรือ superset ของ ASCII แต่มีตัวเลข 10 หลักเหมือนกันใน ASCII เท่านั้นที่มีการแทนค่าบิตที่แตกต่างกัน (EBCDIC)) \d
ในทางกลับกันอาจเป็นเพียงตัวเลขหลัก (Perl รุ่นเก่าหรือ Perl รุ่นใหม่ที่มี/a
การเปิดใช้งานการแสดงออกปกติ) หรืออาจเป็นการจับคู่แบบ Unicode \p{Digit}
ซึ่งค่อนข้างเป็นชุดตัวเลขขนาดใหญ่กว่า[0-9]
หรือ/\d/a
จับคู่
$ perl -E 'say "match" if 42 =~ m/\d/'
match
$ perl -E 'say "match" if "\N{U+09EA}" =~ m/\d/'
match
$ perl -E 'say "match" if "\N{U+09EA}" =~ m/\d/a'
$ perl -E 'say "match" if "\N{U+09EA}" =~ m/[0-9]/'
$
perldoc perlrecharclass
สำหรับข้อมูลเพิ่มเติมหรือดูเอกสารประกอบของภาษาที่เป็นปัญหาเพื่อดูว่ามันทำงานอย่างไร
แต่เดี๋ยวก่อนมีอีกมาก! สถานที่เกิดเหตุนอกจากนี้ยังอาจแตกต่างกันไปในสิ่งที่\d
ตรงกับดังนั้น\d
อาจไม่ตรงกับตัวเลขน้อยกว่าชุดที่สมบูรณ์ของ Unicode ดังกล่าวและ (หวังว่าปกติ) [0-9]
นอกจากนี้ยังมี สิ่งนี้คล้ายกับความแตกต่างใน C ระหว่างisdigit(3)
( [0-9]
) และisnumber(3)
( [0-9
รวมถึงสิ่งอื่นจากสถานที่)
อาจมีการโทรที่สามารถรับค่าของตัวเลขแม้ว่าจะไม่ใช่[0-9]
:
$ perl -MUnicode::UCD=num -E 'say num(4)'
4
$ perl -MUnicode::UCD=num -E 'say num("\N{U+09EA}")'
4
$
[0-9]
เช่นนี้มันจะบังคับให้ตรงกับที่เหมือนกันและเพียง
ความหมายที่แตกต่างกัน[0-9]
, [[:digit:]]
และ\d
ถูกนำเสนอในคำตอบอื่น ๆ ที่นี่ฉันต้องการเพิ่มความแตกต่างในการใช้งานของเครื่องมือ regex
[[:digit:]] \d
grep -E ✓ ×
grep -P ✓ ✓
sed ✓ ×
sed -E ✓ ×
ดังนั้น[[:digit:]]
การทำงานเสมอ , \d
ขึ้นอยู่กับ ในคู่มือของ grep มีการกล่าวถึงว่า[[:digit:]]
อยู่0-9
ในC
โลแคล
PS1: ถ้าคุณรู้มากขึ้นโปรดขยายตาราง
PS2: GNU grep 3.1 และ GNU 4.4 ใช้สำหรับทดสอบ
grep
และsed
มีความแตกต่างมากที่สุดระหว่าง GNU กับรุ่นอื่น ๆ คำตอบนี้อาจมีประโยชน์มากขึ้นหากกล่าวถึงรุ่นที่grep
และsed
มันหมายถึง หรือแหล่งที่มาของตารางนั้นคืออะไรสำหรับเรื่องนั้น 2) ตารางนั้นอาจถูกถอดความเป็นข้อความเนื่องจากไม่มีสิ่งใดที่ต้องการให้เป็นรูปภาพ
re
โมดูลไพ ธ อนในตัวไม่รองรับ [[: หลัก:]] แต่การเพิ่มในregex
ไลบรารี่รองรับมันดังนั้นฉันจะงอเล็กน้อยที่ใช้งานได้เสมอ มันมักจะทำงานในสถานการณ์การร้องเรียน posix
ความแตกต่างทางทฤษฎีได้รับการอธิบายอย่างดีในคำตอบอื่น ๆ ดังนั้นจึงยังคงอธิบายถึงความแตกต่างในทางปฏิบัติ
ต่อไปนี้เป็นกรณีการใช้งานทั่วไปที่มากขึ้นสำหรับการจับคู่ตัวเลข
บ่อยครั้งเมื่อคุณต้องการกระทืบตัวเลขบางตัวตัวเลขเหล่านั้นจะอยู่ในไฟล์ข้อความที่จัดรูปแบบอย่างเชื่องช้า คุณต้องการแยกมันเพื่อใช้ในโปรแกรมของคุณ คุณอาจบอกรูปแบบตัวเลข (โดยดูที่ไฟล์) และตำแหน่งปัจจุบันของคุณดังนั้นคุณสามารถใช้แบบฟอร์มใด ๆ ได้ตราบใดที่มันทำงานเสร็จ \d
ต้องใช้การกดแป้นที่น้อยที่สุดดังนั้นจึงใช้กันมาก
คุณมีการป้อนข้อมูลของผู้ใช้ที่ไม่น่าเชื่อถือ (อาจมาจากเว็บฟอร์ม) และคุณต้องแน่ใจว่าไม่มีความประหลาดใจใด ๆ บางทีคุณอาจต้องการเก็บไว้ในเขตข้อมูลตัวเลขในฐานข้อมูลหรือใช้เป็นพารามิเตอร์ในคำสั่งเชลล์เพื่อเรียกใช้บนเซิร์ฟเวอร์ ในกรณีนี้คุณต้องการ[0-9]
เพราะมันเป็นข้อ จำกัด และคาดเดาได้มากที่สุด
คุณมีข้อมูลบางส่วนที่คุณจะไม่ใช้กับสิ่งที่ "อันตราย" แต่มันก็ดีถ้ารู้ว่ามันมีจำนวนมาก ตัวอย่างเช่นโปรแกรมของคุณอนุญาตให้ผู้ใช้ป้อนที่อยู่และคุณต้องการไฮไลท์ตัวพิมพ์ที่เป็นไปได้หากข้อมูลที่ป้อนไม่มีหมายเลขบ้าน ในกรณีนี้คุณอาจต้องการให้กว้างที่สุดเท่าที่[[:digit:]]
จะเป็นไปได้
ดูเหมือนจะเป็นกรณีการใช้งานที่พบมากที่สุดสามกรณีสำหรับการจับคู่แบบหลัก หากคุณคิดว่าฉันพลาดสิ่งสำคัญโปรดส่งความคิดเห็น