บางครั้งฉันต้องการจับคู่ช่องว่าง แต่ไม่ขึ้นบรรทัดใหม่
จนถึงตอนนี้ฉันก็หันไป[ \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 \h8 เป็นที่ยอมรับว่าเป็นกรณีขอบ
ใช้ลบสองครั้ง:
/[^\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}
เมื่อเทียบกับที่คล้ายกัน\hPOSIX 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]"ช่องว่าง"