Đôi khi tôi muốn khớp với khoảng trắng nhưng không phải dòng mới.
Cho đến nay tôi đã dùng đến [ \t]
. Có một cách ít khó xử hơn?
Đôi khi tôi muốn khớp với khoảng trắng nhưng không phải dòng mới.
Cho đến nay tôi đã dùng đến [ \t]
. Có một cách ít khó xử hơn?
Câu trả lời:
Các phiên bản Perl 5.10 trở lên hỗ trợ các lớp ký tự dọc và ngang của công ty con, \v
và \h
, cũng như lớp ký tự khoảng trắng chung\s
Giải pháp sạch nhất là sử dụng lớp ký tự khoảng trắng ngang\h
. Điều này sẽ khớp với tab và không gian từ bộ ASCII, không gian không phá vỡ từ ASCII mở rộng hoặc bất kỳ ký tự Unicode nào trong số này
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
Các không gian dọc mẫu \v
là ít hữu ích, nhưng phù hợp với những nhân vật
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
Có bảy ký tự khoảng trắng dọc phù hợp \v
và mười tám ký tự ngang phù hợp \h
. \s
phù hợp với hai mươi ba nhân vật
Tất cả các ký tự khoảng trắng là dọc hoặc ngang không có chồng chéo, nhưng chúng không phải là tập hợp con phù hợp vì \h
cũng khớp với KHÔNG GIAN U + 00A0 NO-BREAK và \v
cũng khớp với U + 0085 TIẾP THEO, không khớp nào\s
\h
chỉ hoạt động trên các ngôn ngữ hỗ trợ PCRE
.
[[:blank:]]
không phù hợp với không gian nghỉ -
hoặc"\xA0"
\h
hoạt động hoàn hảo cho trường hợp sử dụng của tôi đang thực hiện tìm / thay thế trong Notepad ++ trên 1 hoặc nhiều không gian không phải dòng mới liền kề. Không có gì khác (đơn giản) làm việc.
\h
hơi không chuẩn là sự bao gồm của nó MONGOLIAN VOWEL SEPARATOR
. Unicode không coi đó là khoảng trắng. Vì lý do đó, Perl \h
khác với POSIX blank
( [[:blank:]]
trong Perl, \p{Blank}
trong Java) và Java 8 \h
. Phải thừa nhận rằng đó là một trường hợp cạnh.
Sử dụng phủ định kép:
/[^\S\r\n]/
Đó là, không-không-khoảng trắng (vốn S bổ sung) hoặc không-vận chuyển-trở lại hoặc không-dòng mới. Phân phối bên ngoài không ( nghĩa là bổ sung ^
trong lớp nhân vật) theo luật của De Morgan , điều này tương đương với khoảng trắng của nhưng không trả lại vận chuyển hoặc dòng mới. Bao gồm cả hai \r
và \n
trong mẫu xử lý chính xác tất cả các quy ước dòng mới Unix (LF), Mac OS (CR) và DOS-ish (CR LF) .
Không cần phải lấy lời của tôi cho nó:
#! /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";
}
Đầu ra:
"" => khớp "\ f" => khớp "\ t" => khớp "\ r" => không khớp "\ n" => không khớp
Lưu ý loại trừ tab dọc, nhưng điều này được đề cập trong v5.18 .
Trước khi phản đối quá gay gắt, tài liệu Perl sử dụng kỹ thuật tương tự. Một chú thích trong phần Whitespace Lần lượt của Perlrechar class đọc
Trước Perl v5.18,
\s
không khớp với tab dọc.[^\S\cK]
(tối nghĩa) phù hợp với những gì\s
truyền thống đã làm.
Phần tương tự của perlrechar class cũng gợi ý các cách tiếp cận khác không xúc phạm sự phản đối của giáo viên ngôn ngữ đối với các tiêu cực kép.
Các quy tắc ngôn ngữ và ngôn ngữ Unicode bên ngoài hoặc khi công /a
tắc có hiệu lực, \s
phù hợp [\t\n\f\r ]
và, bắt đầu từ Perl v5.18, tab dọc , \cK
. Hủy bỏ \r
và \n
để lại /[\t\f\cK ]/
cho phù hợp với khoảng trắng nhưng không phải là dòng mới.
Nếu văn bản của bạn là Unicode, hãy sử dụng mã tương tự như phụ bên dưới để tạo mẫu từ bảng trong phần tài liệu đã nói ở trên .
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;
}
Thủ thuật phủ định kép cũng thuận tiện cho việc ghép các ký tự chữ cái. Hãy nhớ rằng \w
phù hợp với các ký tự từ tiếng Nhật, các ký tự chữ cái và chữ số và dấu gạch dưới. Chúng ta xấu xí - người Mỹ đôi khi muốn viết nó như, nói,
if (/[A-Za-z]+/) { ... }
nhưng một lớp nhân vật tiêu cực kép có thể tôn trọng miền địa phương:
if (/[^\W\d_]+/) { ... }
Thể hiện một ký tự chữ nhưng không phải chữ số hoặc gạch dưới. Cách này hơi mờ. Một lớp nhân vật POSIX truyền đạt ý định trực tiếp hơn
if (/[[:alpha:]]+/) { ... }
hoặc với thuộc tính Unicode như szbalint đề xuất
if (/\p{Letter}+/) { ... }
\r
, ví dụ như trên Windows, vì vậy hãy xem xét loại trừ những người khỏi trận đấu /[^\S\r\n]/
:))
\h
có sẵn.
Một biến thể về câu trả lời của Greg bao gồm cả trả lại vận chuyển:
/[^\S\r\n]/
Regex này an toàn hơn so /[^\S\n]/
với không \r
. Lý do của tôi là Windows sử dụng \r\n
cho dòng mới và Mac OS 9 được sử dụng \r
. Bạn không thể tìm thấy \r
mà không có \n
ngày nay, nhưng nếu bạn tìm thấy nó, nó không có nghĩa gì ngoài một dòng mới. Vì vậy, vì \r
có thể có nghĩa là một dòng mới, chúng ta cũng nên loại trừ nó.
Regex dưới đây sẽ phù hợp với khoảng trắng nhưng không phải là ký tự dòng mới.
(?:(?!\n)\s)
Nếu bạn muốn thêm trở lại vận chuyển cũng sau đó thêm \r
với các |
nhà điều hành bên trong cái nhìn tiêu cực.
(?:(?![\n\r])\s)
Thêm +
sau nhóm không chụp để khớp với một hoặc nhiều khoảng trắng.
(?:(?![\n\r])\s)+
Tôi không biết lý do tại sao mọi người không đề cập đến lớp ký tự POSIX [[:blank:]]
phù hợp với bất kỳ khoảng trắng ngang ( khoảng trắng và tab ) nào. Lớp chracter POSIX này sẽ hoạt động trên BRE ( Biểu thức cơ bản cơ bản ), ERE ( Biểu thức chính quy mở rộng ), PCRE ( Biểu thức chính quy tương thích Perl ).
Những gì bạn đang tìm kiếm là blank
lớp nhân vật POSIX . Trong Perl, nó được tham chiếu là:
[[:blank:]]
trong Java (đừng quên bật UNICODE_CHARACTER_CLASS
):
\p{Blank}
So với tương tự \h
, POSIX blank
được hỗ trợ bởi một vài công cụ regex ( tham khảo ). Một lợi ích chính là định nghĩa của nó được cố định trong Phụ lục C: Thuộc tính tương thích của Biểu thức và tiêu chuẩn Unicode thông thường trên tất cả các hương vị regex hỗ trợ Unicode. (Ví dụ, trong Perl, \h
chọn thêm vào MONGOLIAN VOWEL SEPARATOR
.) Tuy nhiên, một đối số có lợi \h
là nó luôn phát hiện các ký tự Unicode (ngay cả khi các công cụ không đồng ý với điều đó), trong khi các lớp ký tự POSIX thường theo mặc định ASCII -only (như trong Java).
Nhưng vấn đề là ngay cả việc dính vào Unicode cũng không giải quyết được vấn đề 100%. Xem xét các ký tự sau không được coi là khoảng trắng trong Unicode:
U + FEFF ZERO WIDTH KHÔNG GIAN KHÔNG GIAN
Dấu tách nguyên âm Mông Cổ đã nói ở trên không được bao gồm cho những gì có lẽ là một lý do tốt. Nó, cùng với 200C và 200D, xảy ra trong các từ (AFAIK), và do đó phá vỡ quy tắc chính yếu mà tất cả các khoảng trắng khác tuân theo: bạn có thể token hóa nó. Chúng giống như sửa đổi hơn. Tuy nhiên, ZERO WIDTH SPACE
, WORD JOINER
, và ZERO WIDTH NON-BREAKING SPACE
(nếu nó được sử dụng như khác hơn là một dấu byte đặt hàng) phù hợp với những quy tắc khoảng trắng trong cuốn sách của tôi. Do đó, tôi bao gồm chúng trong lớp nhân vật khoảng trắng ngang của tôi.
Trong Java:
static public final String HORIZONTAL_WHITESPACE = "[\\p{Blank}\\u200B\\u2060\\uFFEF]"
perl
thẻ trong câu hỏi ban đầu.
[\p{Blank}\u200b\u180e]
là bắt buộc. Phải thừa nhận rằng, một phân tách nguyên âm không được coi là một ký tự khoảng trắng, nhưng tại sao không gian có độ rộng bằng không không có trong các lớp như \s
và \p{Blank}
, đánh bại tôi.
m/ /g
Chỉ cần cho không gian trong / /
, và nó sẽ làm việc. Hoặc sử dụng \S
- nó sẽ thay thế tất cả các ký tự đặc biệt như tab, dòng mới, dấu cách, v.v.
[\r\f]
.