Cocokkan spasi putih tetapi bukan baris baru

277

Saya terkadang ingin mencocokkan spasi putih tetapi tidak dengan baris baru.

Sejauh ini saya telah menggunakan [ \t]. Apakah ada cara yang kurang canggung?

JoelFan
sumber
4
BTW, karakter ini juga "spasi": [\r\f].
Eugene Yarmash
2
@eugeney adakah yang masih melakukan feed form? (\ f's)
Aran Mulholland
1
@AranMulholland: Siapa pun yang memiliki printer yang berorientasi karakter. Sebagian besar printer memiliki mode karakter serta PostScript atau apa pun yang disebut antarmuka Hewlett Packard, dan untuk melempar halaman Anda mengirim umpan formulir.
Borodin
1
@Borodin Hewlett Packard disebut PCL (Printer Control Language).
CB_R

Jawaban:

182

Perl versi 5.10 dan yang lebih baru mendukung kelas karakter vertikal dan horizontal, \vdan \h, juga kelas karakter spasi putih generik\s

Solusi terbersih adalah menggunakan kelas karakter spasi putih horizontal\h . Ini akan mencocokkan tab dan ruang dari set ASCII, ruang tanpa putus dari ASCII yang diperluas, atau salah satu dari karakter Unicode ini

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

The ruang vertikal pola \vkurang berguna, tapi cocok karakter ini

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

Ada tujuh karakter spasi putih vertikal yang cocok \vdan delapan belas karakter horizontal yang cocok \h. \scocok dengan dua puluh tiga karakter

Semua karakter spasi putih baik vertikal atau horizontal tanpa tumpang tindih, tetapi mereka bukan himpunan bagian yang tepat karena \hjuga cocok dengan U + 00A0 NO-BREAK SPACE, dan \vjuga cocok dengan U + 0085 LINE NEXT, yang keduanya tidak cocok dengan\s

Borodin
sumber
7
\hhanya berfungsi pada bahasa yang mendukung PCRE.
Avinash Raj
14
@AvinashRaj: Pertanyaan ini tentang Perl, yang tentu saja mendukung PCRE
Borodin
2
@AvinashRaj: Kecuali itu [[:blank:]]tidak cocok dengan ruang tanpa istirahat -  atau"\xA0"
Borodin
6
Ingin menyebutkan yang \hberfungsi dengan baik untuk use case saya yang sedang melakukan find / replace di Notepad ++ pada 1 atau lebih ruang baris non-baru yang bersebelahan. Tidak ada yang lain (sederhana) yang berfungsi.
squidbe
8
Yang membuat Perl \hsedikit tidak standar adalah dimasukkannya MONGOLIAN VOWEL SEPARATOR. Unicode tidak menganggapnya sebagai spasi putih. Untuk alasan itu, Perl \hberbeda dari POSIX blank( [[:blank:]]dalam Perl, \p{Blank}di Jawa) dan Java 8 \h. Memang, ini kasus tepi.
Aleksandr Dubinsky
362

Gunakan double-negatif:

/[^\S\r\n]/

Yaitu, bukan-bukan-spasi putih (ibukota S melengkapi) atau tidak-carriage-return atau tidak-newline. Mendistribusikan bagian luar tidak ( yaitu , pelengkap ^dalam kelas karakter) dengan hukum De Morgan , ini setara dengan "spasi putih tetapi bukan carriage return atau newline." Termasuk keduanya \rdan \ndalam pola dengan benar menangani semua konvensi baris baru Unix (LF), Mac OS (CR) klasik, dan DOS-ish (CR LF) .

Tidak perlu mengambil kata saya untuk itu:

#! /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";
}

Keluaran:

"" => cocok
"\ f" => cocok
"\ t" => cocok
"\ r" => tidak cocok
"\ n" => tidak cocok

Perhatikan pengecualian tab vertikal, tetapi ini dibahas dalam v5.18 .

Sebelum menolak terlalu keras, dokumentasi Perl menggunakan teknik yang sama. Catatan kaki di bagian “Ruang Putih” perlrecharclass berbunyi

Sebelum Perl v5.18, \stidak cocok dengan tab vertikal. [^\S\cK](Jelas) cocok dengan apa yang secara \stradisional dilakukan.

The bagian yang sama dari perlrecharclass juga menunjukkan pendekatan lain yang tidak akan menyinggung oposisi guru bahasa untuk double-negatif.

Di luar lokal dan aturan Unicode atau ketika /asakelar berlaku, " \scocok [\t\n\f\r ]dan, mulai di Perl v5.18, tab vertikal \cK,." Buang \rdan \ntinggalkan /[\t\f\cK ]/untuk pencocokan spasi putih tetapi bukan baris baru.

Jika teks Anda adalah Unicode, gunakan kode yang mirip dengan sub di bawah ini untuk membuat pola dari tabel di bagian dokumentasi yang disebutkan di atas .

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;
}

Aplikasi lain

Trik ganda negatif juga berguna untuk mencocokkan karakter alfabet juga. Ingat bahwa \wcocok dengan "karakter kata," karakter dan digit alfabet dan garis bawah. Kami orang Amerika yang jelek kadang ingin menuliskannya sebagai, katakanlah,

if (/[A-Za-z]+/) { ... }

tetapi kelas karakter ganda-negatif dapat menghormati lokal:

if (/[^\W\d_]+/) { ... }

Mengekspresikan "karakter kata tetapi bukan angka atau garis bawah" dengan cara ini agak buram. Kelas karakter POSIX mengkomunikasikan maksud secara lebih langsung

if (/[[:alpha:]]+/) { ... }

atau dengan properti Unicode seperti yang disarankan szbalint

if (/\p{Letter}+/) { ... }
Greg Bacon
sumber
4
Pintar, tetapi perilakunya sangat mengejutkan, dan saya tidak melihat bagaimana hal itu kurang canggung.
Qwertie
7
@ Qwertie: apa yang mengejutkan? Kurang canggung dari apa?
ysth
9
Sangat buruk.
9
Ini sangat bagus. Seperti yang diminta, Anda mencocokkan spasi putih (bukan hanya beberapa karakter spasi putih), dan Anda mengecualikan karakter umpan baris. Solusi Anda tidak berkaitan dengan pertanyaan: "karakter spasi apa yang ada", sebagaimana seharusnya. Inilah tepatnya yang saya cari. (Sebagaimana dicatat oleh @Rory, sebuah 'baris baru' mungkin juga termasuk \r, misalnya pada Windows, sehingga mempertimbangkan exluding mereka dari pertandingan juga: /[^\S\r\n]/)
Timo
1
Ini tentunya akan memenuhi kebutuhan OP dan hampir semua orang yang mencari pertanyaan ini (bagaimanapun juga, penutur bahasa Inggris). Tapi itu masih jawaban yang buruk. Tidak ada alasan untuk menggunakan solusi ini ketika \htersedia.
Alan Moore
50

Variasi jawaban Greg yang mencakup carriage return juga:

/[^\S\r\n]/

Regex ini lebih aman daripada /[^\S\n]/tanpa \r. Alasan saya adalah bahwa Windows menggunakan \r\nbaris baru, dan Mac OS 9 digunakan \r. Anda tidak akan menemukannya \rtanpa \nsaat ini, tetapi jika Anda menemukannya, itu tidak bisa berarti apa-apa selain baris baru. Jadi, karena \rdapat berarti baris baru, kita juga harus mengecualikannya.

Rory O'Kane
sumber
1
1 Solusi Greg akhirnya merusak teks saya, milik Anda bekerja dengan baik.
Timo Huovinen
Anda mungkin terkejut dengan berapa banyak program yang masih menggunakan "\ r" untuk akhiran baris. Terkadang saya butuh waktu untuk mengetahui bahwa masalah saya adalah file yang digunakan ini. Atau menggunakan penyandian karakter MacRoman ...
mivk
2
Sepertinya @Greg pertama kali "salah" mengubahnya dan tidak memuji Anda. Itulah mengapa saya tidak setuju di sini.
Andre Elrico
14

Regex di bawah ini akan cocok dengan spasi putih tetapi tidak dengan karakter garis baru.

(?:(?!\n)\s)

DEMO

Jika Anda ingin menambahkan carriage return juga maka tambahkan \rdengan |operator di dalam lookahead negatif.

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

DEMO

Tambahkan +setelah grup yang tidak menangkap untuk mencocokkan satu atau lebih spasi putih.

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

DEMO

Saya tidak tahu mengapa kalian gagal menyebutkan kelas karakter POSIX [[:blank:]]yang cocok dengan spasi putih spasi ( spasi dan tab ). Kelas chracter POSIX ini akan bekerja pada BRE ( Basic REgular Expressions ), ERE ( Extended Regular Expression ), PCRE ( Perl Kompatibel Regular Expression ).

DEMO

Avinash Raj
sumber
Ini solusi terbaik!
loretoparisi
13

Apa yang Anda cari adalah blankkelas karakter POSIX . Dalam Perl itu dirujuk sebagai:

[[:blank:]]

di Jawa (jangan lupa untuk mengaktifkan UNICODE_CHARACTER_CLASS):

\p{Blank}

Dibandingkan dengan yang serupa \h, POSIX blankdidukung oleh beberapa mesin regex ( referensi ). Manfaat utama adalah bahwa definisi tersebut ditetapkan dalam Lampiran C: Properti Kompatibilitas Unicode Regular Expressions dan standar di semua rasa regex yang mendukung Unicode. (Dalam Perl, misalnya, \hmemilih untuk menyertakan tambahan MONGOLIAN VOWEL SEPARATOR.) Namun, argumen yang mendukung \hadalah bahwa ia selalu mendeteksi karakter Unicode (bahkan jika mesin tidak setuju dengan yang), sementara kelas karakter POSIX sering secara default ASCII -hanya (seperti di Jawa).

Tetapi masalahnya adalah bahwa bahkan tetap pada Unicode tidak menyelesaikan masalah 100%. Pertimbangkan karakter berikut yang tidak dianggap sebagai spasi putih di Unicode:

Pemisah vokal Mongolia yang disebutkan di atas tidak termasuk untuk alasan yang mungkin bagus. Itu, bersama dengan 200C dan 200D, terjadi dalam kata-kata (AFAIK), dan karena itu melanggar aturan kardinal yang dipatuhi oleh semua spasi putih lainnya: Anda dapat melakukan tokenize dengannya. Mereka lebih seperti pengubah. Namun, ZERO WIDTH SPACE, WORD JOINER, dan ZERO WIDTH NON-BREAKING SPACE(jika digunakan sebagai selain tanda byte-order) sesuai dengan aturan spasi dalam buku saya. Oleh karena itu, saya memasukkan mereka dalam kelas karakter spasi putih horizontal saya.

Di Jawa:

static public final String HORIZONTAL_WHITESPACE = "[\\p{Blank}\\u200B\\u2060\\uFFEF]"
Aleksandr Dubinsky
sumber
Anda perlu menambahkan flag kompilasi regexp yang sesuai ke kompilasi Java, dan menjalankan Java 7 atau lebih baru. Bagaimanapun, pertanyaannya bukan tentang Java atau PCRE sama sekali, jadi ini semua tidak penting.
tchrist
@tchrist Terima kasih telah menunjukkan ini. Saya akan memperbarui jawaban saya. Namun, saya tidak setuju bahwa jawaban saya tidak relevan. Apa yang tidak penting adalah perltanda pada pertanyaan awal.
Aleksandr Dubinsky
1
@AleksandrDubinsky, \ p {Blank} tidak didukung dalam JavaScript, jadi jelas tidak "standar untuk semua rasa regex" -1
Valentin Vasilyev
Paling informatif. Saya merasa terganggu untuk mengetahui bahwa kelas karakter steno "horizontal whitespace" umum dan lengkap tidak ada, dan bahwa kengerian seperti [\p{Blank}\u200b\u180e]diperlukan. Diakui, masuk akal bahwa pemisah vokal tidak dianggap sebagai karakter spasi, tetapi mengapa ruang lebar nol tidak di kelas seperti \sdan \p{Blank}, mengalahkan saya.
Timo
Tindak lanjut: Saya membaca bahwa keduanya dianggap 'batas netral', meskipun itu tidak menjelaskan mengapa .
Timo
-4

m/ /gcukup beri ruang / /, dan itu akan berhasil. Atau gunakan \S- ini akan menggantikan semua karakter khusus seperti tab, baris baru, spasi, dan sebagainya.

saiprathapreddy.obula
sumber