บางครั้งฉันต้องการจับคู่ช่องว่าง แต่ไม่ขึ้นบรรทัดใหม่
จนถึงตอนนี้ฉันก็หันไป[ \t]
ใช้ มีวิธีที่น่าอึดอัดใจน้อยลงหรือไม่?
บางครั้งฉันต้องการจับคู่ช่องว่าง แต่ไม่ขึ้นบรรทัดใหม่
จนถึงตอนนี้ฉันก็หันไป[ \t]
ใช้ มีวิธีที่น่าอึดอัดใจน้อยลงหรือไม่?
คำตอบ:
รุ่น Perl 5.10 และต่อมาการสนับสนุน บริษัท ย่อยชั้นเรียนตัวอักษรในแนวตั้งและแนวนอน\v
และ\h
เช่นเดียวกับช่องว่างทั่วไปตัวละครคลาส\s
วิธีการแก้ปัญหาที่สะอาดคือการใช้ช่องว่างในแนวนอน\h
ตัวละครคลาส สิ่งนี้จะจับคู่แท็บและช่องว่างจากชุด ASCII, พื้นที่ไม่แตกจาก ASCII ที่ขยายออกมาหรืออักขระ Unicode ใด ๆ เหล่านี้
U+0009 CHARACTER TABULATION
U+0020 SPACE
U+00A0 NO-BREAK SPACE (not matched by \s)
U+1680 OGHAM SPACE MARK
U+2000 EN QUAD
U+2001 EM QUAD
U+2002 EN SPACE
U+2003 EM SPACE
U+2004 THREE-PER-EM SPACE
U+2005 FOUR-PER-EM SPACE
U+2006 SIX-PER-EM SPACE
U+2007 FIGURE SPACE
U+2008 PUNCTUATION SPACE
U+2009 THIN SPACE
U+200A HAIR SPACE
U+202F NARROW NO-BREAK SPACE
U+205F MEDIUM MATHEMATICAL SPACE
U+3000 IDEOGRAPHIC SPACE
พื้นที่ตามแนวตั้งรูปแบบ\v
จะเป็นประโยชน์น้อย แต่ตรงกับตัวละครเหล่านี้
U+000A LINE FEED
U+000B LINE TABULATION
U+000C FORM FEED
U+000D CARRIAGE RETURN
U+0085 NEXT LINE (not matched by \s)
U+2028 LINE SEPARATOR
U+2029 PARAGRAPH SEPARATOR
มีเจ็ดตัวอักษรช่องว่างในแนวตั้งที่ตรงกันและสิบแปดคนในแนวนอนซึ่งการแข่งขัน\v
ตรงกับตัวละครยี่สิบสาม\h
\s
อักขระช่องว่างทั้งหมดเป็นแนวตั้งหรือแนวนอนโดยไม่ทับซ้อนกัน แต่เป็นเซตย่อยที่ไม่เหมาะสมเพราะ\h
ตรงกับ U + 00A0 NO-BREAK SPACE และ\v
ตรงกับ U + 0085 NEXT LINE ซึ่งไม่ตรงกับ\s
\h
ใช้งานได้กับภาษาที่รองรับPCRE
เท่านั้น
[[:blank:]]
ไม่ตรงกับที่ไม่มีช่องว่าง -
หรือ"\xA0"
\h
ทำงานได้อย่างสมบูรณ์แบบสำหรับกรณีการใช้งานของฉันซึ่งทำการค้นหา / แทนที่ใน Notepad ++ บนพื้นที่ว่างที่ไม่ใช่บรรทัดใหม่ที่อยู่ติดกันอย่างน้อย 1 บรรทัด ไม่มีอะไรทำงาน (ง่าย)
\h
ไม่ได้มาตรฐานเล็กน้อยคือการรวมเข้าไว้MONGOLIAN VOWEL SEPARATOR
ด้วย Unicode ไม่ถือว่าเป็นช่องว่าง สำหรับเหตุผลที่ Perl \h
แตกต่างจาก POSIX blank
( [[:blank:]]
ใน Perl, \p{Blank}
ในชวา) และ Java \h
8 เป็นที่ยอมรับว่าเป็นกรณีขอบ
ใช้ลบสองครั้ง:
/[^\S\r\n]/
นั่นคือไม่ใช่ช่องว่าง (ตัวเสริม S) หรือไม่ใช่สายการบินส่งคืนหรือไม่ขึ้นบรรทัดใหม่ การกระจายด้านนอกไม่ใช่ ( เช่นการเติมเต็ม^
ในคลาสอักขระ) ด้วยกฎของเดมอร์แกนนี่เทียบเท่ากับ“ ช่องว่าง แต่ไม่ใช่สายการบินส่งคืนหรือขึ้นบรรทัดใหม่” การรวมทั้ง\r
และ\n
ในรูปแบบถูกต้องจัดการ Unix (LF) คลาสสิก Mac OS (CR) และ DOS-ish (CR LF) ข้อตกลงใหม่ทั้งหมด
ไม่จำเป็นต้องใช้คำพูดของฉันมัน:
#! /usr/bin/env perl
use strict;
use warnings;
use 5.005; # for qr//
my $ws_not_crlf = qr/[^\S\r\n]/;
for (' ', '\f', '\t', '\r', '\n') {
my $qq = qq["$_"];
printf "%-4s => %s\n", $qq,
(eval $qq) =~ $ws_not_crlf ? "match" : "no match";
}
เอาท์พุท:
"" => จับคู่ "\ f" => จับคู่ "\ t" => จับคู่ "\ r" => ไม่ตรงกัน "\ n" => ไม่ตรงกัน
หมายเหตุยกเว้นของแท็บแนวตั้ง แต่นี่คือการแก้ไขใน v5.18
ก่อนที่จะคัดค้านอย่างรุนแรงเกินไปเอกสารประกอบ Perl ใช้เทคนิคเดียวกัน เชิงอรรถในส่วน"ช่องว่าง" ของ perlrecharclassอ่าน
ก่อนหน้า Perl v5.18
\s
ไม่ตรงกับแท็บแนวตั้ง[^\S\cK]
(คลุมเครือ) ตรงกับสิ่งที่\s
ทำตามธรรมเนียม
ส่วนที่เหมือนกันของ perlrecharclassยังแนะนำวิธีการอื่น ๆ ที่จะไม่ขัดต่อความขัดแย้งของครูผู้สอนภาษาต่อการลบสองชั้น
นอกกฎโลแคลและ Unicode หรือเมื่อ/a
สวิตช์มีผลบังคับใช้“ \s
จับคู่[\t\n\f\r ]
และเริ่มต้นใน Perl v5.18 แท็บแนวตั้ง\cK
” ยกเลิก\r
และ\n
ออกจาก/[\t\f\cK ]/
การจับคู่ของช่องว่าง แต่ไม่ขึ้นบรรทัดใหม่
ถ้าข้อความของคุณเป็น Unicode ใช้รหัสคล้ายกับการย่อยด้านล่างเพื่อสร้างรูปแบบจากตารางในส่วนเอกสารดังกล่าวข้างต้น
sub ws_not_nl {
local($_) = <<'EOTable';
0x0009 CHARACTER TABULATION h s
0x000a LINE FEED (LF) vs
0x000b LINE TABULATION vs [1]
0x000c FORM FEED (FF) vs
0x000d CARRIAGE RETURN (CR) vs
0x0020 SPACE h s
0x0085 NEXT LINE (NEL) vs [2]
0x00a0 NO-BREAK SPACE h s [2]
0x1680 OGHAM SPACE MARK h s
0x2000 EN QUAD h s
0x2001 EM QUAD h s
0x2002 EN SPACE h s
0x2003 EM SPACE h s
0x2004 THREE-PER-EM SPACE h s
0x2005 FOUR-PER-EM SPACE h s
0x2006 SIX-PER-EM SPACE h s
0x2007 FIGURE SPACE h s
0x2008 PUNCTUATION SPACE h s
0x2009 THIN SPACE h s
0x200a HAIR SPACE h s
0x2028 LINE SEPARATOR vs
0x2029 PARAGRAPH SEPARATOR vs
0x202f NARROW NO-BREAK SPACE h s
0x205f MEDIUM MATHEMATICAL SPACE h s
0x3000 IDEOGRAPHIC SPACE h s
EOTable
my $class;
while (/^0x([0-9a-f]{4})\s+([A-Z\s]+)/mg) {
my($hex,$name) = ($1,$2);
next if $name =~ /\b(?:CR|NL|NEL|SEPARATOR)\b/;
$class .= "\\N{U+$hex}";
}
qr/[$class]/u;
}
เคล็ดลับการลบสองครั้งยังมีประโยชน์สำหรับการจับคู่อักขระที่เป็นตัวอักษรเช่นกัน จำไว้ว่า\w
ตรงกับ“ ตัวอักษรคำ” ตัวอักษรและตัวเลขและขีดเส้นใต้ เราน่าเกลียดคนอเมริกันบางครั้งต้องการเขียนเป็นพูด
if (/[A-Za-z]+/) { ... }
แต่คลาสอักขระที่มีค่าลบสองเท่าสามารถเคารพโลแคลได้:
if (/[^\W\d_]+/) { ... }
การแสดง“ คำตัวอักษร แต่ไม่ใช่ตัวเลขหรือขีดเส้นใต้” วิธีนี้เป็นบิตทึบแสง คลาสอักขระ POSIX สื่อสารจุดประสงค์เพิ่มเติมโดยตรง
if (/[[:alpha:]]+/) { ... }
หรือด้วยคุณสมบัติ Unicode ตามที่แนะนำszbalint
if (/\p{Letter}+/) { ... }
\r
เช่นใน Windows ดังนั้นให้พิจารณาการยกเว้นเหล่านั้นจากการแข่งขันด้วยเช่นกัน/[^\S\r\n]/
)
\h
พร้อมใช้งาน
ความหลากหลายของคำตอบของ Gregซึ่งรวมถึง carriage return ด้วย:
/[^\S\r\n]/
regex นี้ปลอดภัยกว่าไม่มี/[^\S\n]/
\r
เหตุผลของฉันคือการที่ Windows ใช้\r\n
สำหรับการขึ้นบรรทัดใหม่และ Mac OS 9 \r
ใช้ คุณไม่น่าจะพบ\r
ได้\n
ทุกวันนี้ แต่ถ้าคุณพบมันก็ไม่ได้แปลความหมายอะไรเลยนอกจากบรรทัดใหม่ ดังนั้นเนื่องจาก\r
อาจหมายถึงการขึ้นบรรทัดใหม่เราจึงควรยกเว้นเช่นกัน
regex ด้านล่างจะจับคู่ช่องว่างสีขาว แต่ไม่ใช่อักขระบรรทัดใหม่
(?:(?!\n)\s)
หากคุณต้องการเพิ่มการขึ้นบรรทัดใหม่ให้เพิ่ม\r
ด้วยตัว|
ดำเนินการภายใน lookahead เชิงลบ
(?:(?![\n\r])\s)
เพิ่ม+
หลังจากกลุ่มที่ไม่ได้จับภาพเพื่อจับคู่ช่องว่างสีขาวหนึ่งช่องหรือมากกว่า
(?:(?![\n\r])\s)+
ฉันไม่รู้ว่าทำไมคนคุณถึงไม่พูดถึงคลาสตัวอักษร POSIX [[:blank:]]
ที่ตรงกับช่องว่างแนวนอนใด ๆ ( ช่องว่างและแท็บ ) คลาส chracter ของ POSIX นี้จะทำงานกับ BRE ( นิพจน์เรขาพื้นฐาน ), ERE ( นิพจน์ทั่วไปแบบขยาย ), PCRE ( Perl Compatible Regular Expression )
สิ่งที่คุณกำลังค้นหาคือblank
คลาสอักขระPOSIX ใน Perl มันถูกอ้างอิงเป็น:
[[:blank:]]
ใน Java (อย่าลืมเปิดใช้งานUNICODE_CHARACTER_CLASS
):
\p{Blank}
เมื่อเทียบกับที่คล้ายกัน\h
POSIX blank
ได้รับการสนับสนุนโดยเอ็นจิน regex เพิ่มเติมอีกสองสามตัว ( อ้างอิง ) ประโยชน์ที่สำคัญคือคำจำกัดความถูกแก้ไขในภาคผนวก C: คุณสมบัติความเข้ากันได้ของ Unicode การแสดงออกปกติและมาตรฐานในทุกรสชาติของ regex ที่สนับสนุน Unicode (ตัวอย่างเช่นใน Perl \h
เลือกที่จะใส่เครื่องหมายMONGOLIAN VOWEL SEPARATOR
เพิ่มเติม) อย่างไรก็ตามอาร์กิวเมนต์ที่สนับสนุน\h
ก็คือมันจะตรวจจับอักขระ Unicode เสมอ (แม้ว่าเอนจินจะไม่เห็นด้วยกับที่) ในขณะที่คลาส POSIX มักจะเป็น ASCII - เท่านั้น (เช่นใน Java)
แต่ปัญหาคือแม้การเกาะกับ Unicode จะไม่สามารถแก้ปัญหาได้ 100% พิจารณาตัวละครต่อไปนี้ซึ่งไม่ถือว่าเป็นช่องว่างใน Unicode:
ตัวแยกสระมองโกเลีย + 180E
U + 200B ZERO WIDTH SPACE
U + 200C ศูนย์กว้างไม่เข้าร่วม
U + 200D ZERO WIDTH JOINER
U + 2060 WORD JOINER
U + FEFF ZERO กับพื้นที่ว่างเปล่า
ตัวคั่นสระมองโกเลียดังกล่าวไม่รวมอยู่ในสิ่งที่อาจเป็นเหตุผลที่ดี มันพร้อมกับ 200C และ 200D เกิดขึ้นภายในคำ (AFAIK) และดังนั้นจึงแบ่งกฎสำคัญที่ช่องว่างอื่น ๆ ทั้งหมดเชื่อฟัง: คุณสามารถโทเค็นกับมัน พวกมันเป็นเหมือนตัวดัดแปลง อย่างไรก็ตามZERO WIDTH SPACE
, WORD JOINER
และZERO WIDTH NON-BREAKING SPACE
(ถ้าใช้เป็นอื่นที่ไม่ใช่เครื่องหมายสั่งไบต์) พอดีกับกฎช่องว่างในหนังสือของฉัน ดังนั้นฉันรวมไว้ในคลาสอักขระช่องว่างแนวนอน
ใน Java:
static public final String HORIZONTAL_WHITESPACE = "[\\p{Blank}\\u200B\\u2060\\uFFEF]"
perl
แท็กในคำถามเดิมไม่มีสาระสำคัญอะไร
[\p{Blank}\u200b\u180e]
ต้องมีความน่ากลัวเช่นนั้น เป็นที่ยอมรับกันแล้วว่ารู้สึกว่าตัวแยกสระไม่ถือว่าเป็นอักขระช่องว่าง แต่ทำไมพื้นที่ว่างที่มีความกว้างเป็นศูนย์ไม่ได้อยู่ในคลาสที่ชอบ\s
และ\p{Blank}
ทำให้ฉันเต้น
m/ /g
เพียงแค่ให้พื้นที่ใน/ /
และมันจะทำงาน หรือใช้\S
- มันจะแทนที่อักขระพิเศษทั้งหมดเช่นแท็บบรรทัดใหม่ช่องว่างและอื่น ๆ
[\r\f]
"ช่องว่าง"