Khớp khoảng trắng nhưng không phải dòng mới


277

Đô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?


4
BTW, các ký tự này cũng là "khoảng trắng" : [\r\f].
Eugene Yarmash

2
@eugeney có ai còn làm thức ăn không? (\ f ')
Aran Mulholland

1
@AranMulholland: Bất cứ ai có máy in hướng nhân vật. Hầu hết các máy in đều có chế độ ký tự cũng như PostScript hoặc bất kỳ giao diện Hewlett Packard nào được gọi và để ném trang bạn gửi nguồn cấp dữ liệu biểu mẫu.
Borodin

1
@Borodin Hewlett Packard được gọi là PCL (Ngôn ngữ điều khiển máy in).
CB_Ron

Câu trả lời:


182

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\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 \vlà í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 \vvà mười tám ký tự ngang phù hợp \h. \sphù 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ì \hcũng khớp với KHÔNG GIAN U + 00A0 NO-BREAK và \vcũng khớp với U + 0085 TIẾP THEO, không khớp nào\s


7
\hchỉ hoạt động trên các ngôn ngữ hỗ trợ PCRE.
Avinash Raj

14
@AvinashRaj: Câu hỏi này là về Perl, chắc chắn hỗ trợ PCRE
Borodin

2
@AvinashRaj: Ngoại trừ [[:blank:]]không phù hợp với không gian nghỉ -  hoặc"\xA0"
Borodin

6
Muốn đề cập đến \hhoạ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.
câu mực

8
Điều khiến Perl \hhơ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 \hkhá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.
Alexanderr Dubinsky

361

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\ntrong 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, \skhông khớp với tab dọc. [^\S\cK](tối nghĩa) phù hợp với những gì \struyề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 /atắc có hiệu lực, \sphù hợp [\t\n\f\r ]và, bắt đầu từ Perl v5.18, tab dọc , \cK. Hủy bỏ \r\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;
}

Các ứng dụng khác

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 \wphù hợp với các ký tự từ tiếng Nhật, các ký tự chữ cái 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}+/) { ... }

4
Khéo léo, nhưng hành vi rất đáng ngạc nhiên, và tôi không thấy nó bớt khó xử.
Qwertie

7
@Qwertie: có gì đáng ngạc nhiên? Ít khó xử hơn những gì?
ysth

9
Tuyệt vời khủng khiếp.

9
Điều này là rất tốt. Theo yêu cầu, bạn khớp với khoảng trắng (không chỉ một số ký tự khoảng trắng) và bạn loại trừ ký tự nguồn cấp dữ liệu. Giải pháp của bạn không liên quan đến câu hỏi: "những ký tự khoảng trắng nào tồn tại", vì nó không nên. Đây chính xác là những gì tôi đang tìm kiếm. (Như được lưu ý bởi @Rory, một 'dòng mới' cũng có thể bao gồm \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]/:))
Timo

1
Điều này chắc chắn sẽ đáp ứng nhu cầu của OP và hầu như mọi người khác tìm kiếm câu hỏi này (dù sao người nói tiếng Anh). Nhưng đó vẫn là một câu trả lời tồi. Đơn giản là không có lý do gì để sử dụng giải pháp này khi \hcó sẵn.
Alan Moore

49

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\ncho dòng mới và Mac OS 9 được sử dụng \r. Bạn không thể tìm thấy \rmà không có \nngà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ì \rcó thể có nghĩa là một dòng mới, chúng ta cũng nên loại trừ nó.


1
+1 Giải pháp của Greg cuối cùng đã làm hỏng văn bản của tôi, của bạn đã hoạt động tốt.
Timo Huovinen

Bạn có thể ngạc nhiên về số lượng chương trình vẫn sử dụng "\ r" cho các kết thúc dòng. Đôi khi tôi phải mất một thời gian để nhận ra rằng vấn đề của tôi là tập tin đã sử dụng những thứ này. Hoặc là nó đã sử dụng mã hóa ký tự MacRoman ...
mivk

2
Có vẻ như @Greg lần đầu tiên đã "sai" thay đổi nó và không ghi có cho bạn. Đó là lý do tại sao tôi nâng cấp ở đây.
Andre Elrico

14

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)

BẢN GIỚI THIỆU

Nếu bạn muốn thêm trở lại vận chuyển cũng sau đó thêm \rvới các |nhà điều hành bên trong cái nhìn tiêu cực.

(?:(?![\n\r])\s)

BẢN GIỚI THIỆU

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)+

BẢN GIỚI THIỆU

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 ).

BẢN GIỚI THIỆU


Đây là giải pháp tốt nhất!
loretoparisi

13

Những gì bạn đang tìm kiếm là blanklớ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, \hchọn thêm vào MONGOLIAN VOWEL SEPARATOR.) Tuy nhiên, một đối số có lợi \hlà 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:

  • MÁY BAY VOWEL U + 180E MONGOLIAN
  • KHÔNG GIAN UID 200B ZERO
  • U + 200C ZERO WIDTH KHÔNG THAM GIA
  • U + 200D ZERO WIDTH THAM GIA
  • THAM GIA CÔNG VIỆC U + 2060
  • U + FEFF ZERO WIDTH KHÔNG GIAN KHÔNG GIAN

    Lấy từ https://en.wikipedia.org/wiki/White-space_character

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]"

Bạn cần thêm các cờ biên dịch regrec thích hợp vào trình biên dịch Java và đang chạy Java 7 trở lên. Trong mọi trường hợp, câu hỏi hoàn toàn không phải về Java hay PCRE, vì vậy đây hoàn toàn không quan trọng.
tchrist

@tchrist Cảm ơn bạn đã chỉ ra điều này. Tôi sẽ cập nhật câu trả lời của tôi. Tuy nhiên, tôi không đồng ý rằng câu trả lời của tôi là không liên quan. Không quan trọng là perlthẻ trong câu hỏi ban đầu.
Alexanderr Dubinsky

1
@AleksandrDubinsky, \ p {Blank} không được hỗ trợ trong JavaScript, vì vậy chắc chắn không phải là "tiêu chuẩn cho tất cả các hương vị regex" -1
Valentin Vasilyev

Thông tin nhất. Tôi thấy thật đáng lo ngại khi biết rằng một lớp nhân vật tốc ký "khoảng trắng ngang" chung và hoàn chỉnh không tồn tại, và điều kinh khủng đó [\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\p{Blank}, đánh bại tôi.
Timo

Theo dõi: Tôi đọc được rằng cả hai đều được coi là "ranh giới trung lập", mặc dù điều đó không giải thích tại sao .
Timo

-4

m/ /gChỉ 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.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.