Unicode setara untuk \ w dan \ b dalam ekspresi reguler Java?

126

Banyak penerapan ekspresi reguler modern menafsirkan \wsingkatan kelas karakter sebagai "huruf, angka, atau tanda baca apa pun" (biasanya: garis bawah). Dengan cara itu, regex seperti \w+pertandingan kata seperti hello, élève, GOÄ_432atau gefräßig.

Sayangnya, Java tidak. Di Jawa, \wdibatasi hingga [A-Za-z0-9_]. Ini membuat kata-kata yang cocok seperti yang disebutkan di atas menjadi sulit, di antara masalah lainnya.

Tampaknya \bpemisah kata juga cocok di tempat yang tidak semestinya.

Apa yang akan menjadi padanan yang benar dari .NET-like, Unicode-aware \watau \bdi Java? Pintasan lain mana yang perlu "ditulis ulang" untuk membuatnya peka terhadap Unicode?

Tim Pietzcker
sumber
3
Singkatnya, Tim, adalah bahwa mereka semua perlu menulis agar sejalan dengan Unicode. Saya masih tidak melihat tanda-tanda bahwa Java 1.7 akan melakukan lebih banyak hal dengan properti Unicode daripada akhirnya menambahkan dukungan untuk skrip, tetapi hanya itu. Ada beberapa hal yang benar-benar tidak dapat Anda lakukan tanpa akses yang lebih baik ke properti Unicode yang lengkap. Jika Anda belum memiliki saya uniprops dan unichars script (dan uninames ), mereka mata-pembuka menakjubkan dalam semua ini.
tchrist
Seseorang mungkin mempertimbangkan untuk menambahkan tanda pada kelas kata. Sejak misalnya & auml; dapat direpresentasikan dalam Unicode sebagai \ u0061 \ u0308 atau \ u00E4.
Mostowski Runtuh
3
Hai Tim, lihat UPDATE saya. Mereka telah menambahkan bendera agar semuanya berfungsi. Hore!
tchrist

Jawaban:

240

Kode sumber

Kode sumber untuk fungsi penulisan ulang yang saya diskusikan di bawah tersedia di sini .

Update di Java 7

PatternKelas Sun yang diperbarui untuk JDK7 memiliki tanda baru yang luar biasa UNICODE_CHARACTER_CLASS, yang membuat semuanya bekerja dengan baik kembali. Ini tersedia sebagai embeddable (?U)untuk di dalam pola, jadi Anda juga bisa menggunakannya dengan Stringpembungkus kelas. Ini juga menampilkan definisi yang dikoreksi untuk berbagai properti lainnya juga. Sekarang melacak The Unicode Standard, di RL1.2 dan RL1.2a dari UTS # 18: Unicode Regular Expressions . Ini adalah peningkatan yang menarik dan dramatis, dan tim pengembangan patut dipuji atas upaya penting ini.


Masalah Unicode Regex Java

Masalah dengan Java regexes adalah bahwa Perl 1.0 charclass lolos - yang berarti \w, \b, \s, \ddan melengkapi mereka - tidak di Jawa diperpanjang untuk bekerja dengan Unicode. Sendiri di antara ini, \bmenikmati semantik diperpanjang tertentu, tetapi ini tidak memetakan ke \w, atau ke pengidentifikasi Unicode , atau ke properti pemisah baris Unicode .

Selain itu, properti POSIX di Java diakses dengan cara ini:

POSIX syntax    Java syntax

[[:Lower:]]     \p{Lower}
[[:Upper:]]     \p{Upper}
[[:ASCII:]]     \p{ASCII}
[[:Alpha:]]     \p{Alpha}
[[:Digit:]]     \p{Digit}
[[:Alnum:]]     \p{Alnum}
[[:Punct:]]     \p{Punct}
[[:Graph:]]     \p{Graph}
[[:Print:]]     \p{Print}
[[:Blank:]]     \p{Blank}
[[:Cntrl:]]     \p{Cntrl}
[[:XDigit:]]    \p{XDigit}
[[:Space:]]     \p{Space}

Ini adalah berantakan, karena itu berarti bahwa hal-hal seperti Alpha, Lower, dan Spacelakukan tidak di peta Jawa ke Unicode Alphabetic, Lowercaseatau Whitespaceproperti. Ini sangat menjengkelkan. Dukungan properti Unicode Java sangat antemilenial , yang saya maksudkan adalah tidak mendukung properti Unicode yang telah dirilis dalam dekade terakhir.

Tidak dapat berbicara tentang whitespace dengan benar sangat mengganggu. Perhatikan tabel berikut. Untuk setiap poin kode tersebut, ada kolom J-results untuk Java dan kolom P-results untuk Perl atau mesin regex berbasis PCRE lainnya:

             Regex    001A    0085    00A0    2029
                      J  P    J  P    J  P    J  P
                \s    1  1    0  1    0  1    0  1
               \pZ    0  0    0  0    1  1    1  1
            \p{Zs}    0  0    0  0    1  1    0  0
         \p{Space}    1  1    0  1    0  1    0  1
         \p{Blank}    0  0    0  0    0  1    0  0
    \p{Whitespace}    -  1    -  1    -  1    -  1
\p{javaWhitespace}    1  -    0  -    0  -    1  -
 \p{javaSpaceChar}    0  -    0  -    1  -    1  -

Lihat itu?

Hampir setiap hasil spasi putih Java tersebut adalah ̲w̲r̲o̲n̲g̲ menurut Unicode. Ini masalah yang sangat besar. Java hanya kacau, memberikan jawaban yang “salah” menurut praktik yang ada dan juga menurut Unicode. Plus Java bahkan tidak memberi Anda akses ke properti Unicode yang sebenarnya! Faktanya, Java tidak mendukung properti apa pun yang sesuai dengan spasi kosong Unicode.


Solusi untuk Semua Masalah Itu, dan Lainnya

Untuk mengatasi ini dan banyak masalah terkait lainnya, kemarin saya menulis fungsi Java untuk menulis ulang string pola yang menulis ulang 14 pelarian charclass ini:

\w \W \s \S \v \V \h \H \d \D \b \B \X \R

dengan menggantinya dengan hal-hal yang benar-benar berfungsi untuk mencocokkan Unicode dengan cara yang dapat diprediksi dan konsisten. Ini hanya prototipe alfa dari satu sesi peretasan, tetapi sepenuhnya berfungsi.

Singkatnya, kode saya menulis ulang 14 itu sebagai berikut:

\s => [\u0009-\u000D\u0020\u0085\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]
\S => [^\u0009-\u000D\u0020\u0085\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]

\v => [\u000A-\u000D\u0085\u2028\u2029]
\V => [^\u000A-\u000D\u0085\u2028\u2029]

\h => [\u0009\u0020\u00A0\u1680\u180E\u2000-\u200A\u202F\u205F\u3000]
\H => [^\u0009\u0020\u00A0\u1680\u180E\u2000\u2001-\u200A\u202F\u205F\u3000]

\w => [\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]]
\W => [^\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]]

\b => (?:(?<=[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])(?![\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])|(?<![\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])(?=[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]]))
\B => (?:(?<=[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])(?=[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])|(?<![\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]])(?![\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]]))

\d => \p{Nd}
\D => \P{Nd}

\R => (?:(?>\u000D\u000A)|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029])

\X => (?>\PM\pM*)

Beberapa hal yang perlu dipertimbangkan ...

  • Itu menggunakan \Xdefinisi yang Unicode sekarang sebut sebagai cluster grafem warisan , bukan cluster grafem yang diperluas , karena yang terakhir agak lebih rumit. Perl sendiri sekarang menggunakan versi yang lebih bagus, tetapi versi lama masih bisa diterapkan dengan sempurna untuk situasi yang paling umum. EDIT: Lihat addendum di bagian bawah.

  • Apa yang harus dilakukan \dtergantung pada niat Anda, tetapi defaultnya adalah definisi Uniode. Saya dapat melihat orang tidak selalu menginginkan \p{Nd}, tetapi terkadang salah satu [0-9]atau \pN.

  • Dua definisi batas, \bdan \B, secara khusus ditulis untuk menggunakan \wdefinisi tersebut.

  • Itu \wdefinisi terlalu luas, karena meraih huruf parenned bukan hanya yang dilingkari. Other_AlphabeticProperti Unicode tidak tersedia hingga JDK7, jadi itulah yang terbaik yang dapat Anda lakukan.


Menjelajahi Batasan

Batasan telah menjadi masalah sejak Larry Wall pertama kali menciptakan sintaks \bdan \Buntuk membicarakannya untuk Perl 1.0 pada tahun 1987. Kunci untuk memahami bagaimana \bdan \Bkeduanya bekerja adalah untuk menghilangkan dua mitos yang tersebar luas tentang mereka:

  1. Mereka hanya pernah mencari untuk \wkarakter kata, tidak pernah untuk karakter non-kata.
  2. Mereka tidak secara khusus mencari tepi benang.

Sebuah \bbatas berarti:

    IF does follow word
        THEN doesn't precede word
    ELSIF doesn't follow word
        THEN does precede word

Dan itu semua didefinisikan dengan sangat lugas sebagai:

  • mengikuti kata adalah (?<=\w).
  • mendahului kata adalah (?=\w).
  • tidak mengikuti kata adalah (?<!\w).
  • tidak mendahului kata adalah (?!\w).

Oleh karena itu, karena IF-THENdikodekan sebagai and ed-bersama ABdalam ekspresi reguler, an oradalah X|Y, dan karena andlebih diutamakan daripada or, itu sederhana AB|CD. Jadi setiap \bitu berarti batas dapat diganti dengan aman dengan:

    (?:(?<=\w)(?!\w)|(?<!\w)(?=\w))

dengan yang \wditentukan dengan cara yang sesuai.

(Anda mungkin berpikir aneh bahwa Adan Ckomponen berlawanan. Di dunia yang sempurna, Anda seharusnya dapat menulis itu AB|D, tetapi untuk sementara saya mengejar kontradiksi saling pengecualian dalam properti Unicode - yang menurut saya sudah saya tangani , tetapi saya meninggalkan kondisi ganda di perbatasan untuk berjaga-jaga. Ditambah ini membuatnya lebih dapat diperluas jika Anda mendapatkan ide tambahan nanti.)

Untuk \Bnon-batasan, logikanya adalah:

    IF does follow word
        THEN does precede word
    ELSIF doesn't follow word
        THEN doesn't precede word

Mengizinkan semua contoh \Buntuk diganti dengan:

    (?:(?<=\w)(?=\w)|(?<!\w)(?!\w))

Ini benar-benar bagaimana \bdan \Bberperilaku. Pola yang setara untuk mereka adalah

  • \bmenggunakan ((IF)THEN|ELSE)konstruk tersebut(?(?<=\w)(?!\w)|(?=\w))
  • \Bmenggunakan ((IF)THEN|ELSE)konstruk tersebut(?(?=\w)(?<=\w)|(?<!\w))

Tetapi versi dengan hanya AB|CDbaik-baik saja, terutama jika Anda tidak memiliki pola bersyarat dalam bahasa regex Anda - seperti Java. ☹

Saya telah memverifikasi perilaku batas menggunakan ketiga definisi yang setara dengan rangkaian pengujian yang memeriksa 110.385.408 kecocokan per proses, dan yang telah saya jalankan pada selusin konfigurasi data berbeda menurut:

     0 ..     7F    the ASCII range
    80 ..     FF    the non-ASCII Latin1 range
   100 ..   FFFF    the non-Latin1 BMP (Basic Multilingual Plane) range
 10000 .. 10FFFF    the non-BMP portion of Unicode (the "astral" planes)

Namun, orang sering menginginkan jenis batasan yang berbeda. Mereka menginginkan sesuatu yang whitespace dan edge-of-string aware:

  • tepi kiri sebagai(?:(?<=^)|(?<=\s))
  • tepi kanan sebagai(?=$|\s)

Memperbaiki Java dengan Java

Kode yang saya posting di jawaban saya yang lain menyediakan ini dan beberapa kemudahan lainnya. Ini termasuk definisi untuk kata-kata bahasa alami, tanda hubung, tanda hubung, dan apostrof, ditambah sedikit lagi.

Ini juga memungkinkan Anda untuk menentukan karakter Unicode dalam poin kode logis, bukan dalam pengganti UTF-16 idiot. Sulit untuk menekankan betapa pentingnya hal itu! Dan itu hanya untuk ekspansi string.

Untuk substitusi regex charclass yang membuat charclass di regex Java Anda akhirnya berfungsi di Unicode, dan berfungsi dengan benar, ambil sumber lengkapnya dari sini . Anda dapat melakukannya sesuka Anda, tentu saja. Jika Anda memperbaikinya, saya ingin sekali mendengarnya, tetapi Anda tidak perlu melakukannya. Ini sangat singkat. Inti dari fungsi penulisan ulang regex utama sederhana:

switch (code_point) {

    case 'b':  newstr.append(boundary);
               break; /* switch */
    case 'B':  newstr.append(not_boundary);
               break; /* switch */

    case 'd':  newstr.append(digits_charclass);
               break; /* switch */
    case 'D':  newstr.append(not_digits_charclass);
               break; /* switch */

    case 'h':  newstr.append(horizontal_whitespace_charclass);
               break; /* switch */
    case 'H':  newstr.append(not_horizontal_whitespace_charclass);
               break; /* switch */

    case 'v':  newstr.append(vertical_whitespace_charclass);
               break; /* switch */
    case 'V':  newstr.append(not_vertical_whitespace_charclass);
               break; /* switch */

    case 'R':  newstr.append(linebreak);
               break; /* switch */

    case 's':  newstr.append(whitespace_charclass);
               break; /* switch */
    case 'S':  newstr.append(not_whitespace_charclass);
               break; /* switch */

    case 'w':  newstr.append(identifier_charclass);
               break; /* switch */
    case 'W':  newstr.append(not_identifier_charclass);
               break; /* switch */

    case 'X':  newstr.append(legacy_grapheme_cluster);
               break; /* switch */

    default:   newstr.append('\\');
               newstr.append(Character.toChars(code_point));
               break; /* switch */

}
saw_backslash = false;

Bagaimanapun, kode itu hanyalah rilis alfa, hal-hal yang saya retas selama akhir pekan. Tidak akan seperti itu.

Untuk beta saya bermaksud untuk:

  • lipat bersama duplikasi kode

  • menyediakan antarmuka yang lebih jelas mengenai pelarian string yang tidak lolos versus menambah pelarian ekspresi reguler

  • memberikan beberapa fleksibilitas dalam \dperluasan, dan mungkin\b

  • menyediakan metode praktis yang menangani pembalikan dan memanggil Pattern.compile atau String.matches atau yang lainnya untuk Anda

Untuk rilis produksi, harus memiliki javadoc dan rangkaian pengujian JUnit. Saya mungkin menyertakan gigatester saya, tetapi tidak ditulis sebagai tes JUnit.


Tambahan

Saya punya kabar baik dan kabar buruk.

Kabar baiknya adalah bahwa saya sekarang memiliki pendekatan yang sangat dekat dengan cluster grafem yang diperluas untuk digunakan untuk peningkatan \X.

Kabar buruknya ☺ adalah bahwa polanya adalah:

(?:(?:\u000D\u000A)|(?:[\u0E40\u0E41\u0E42\u0E43\u0E44\u0EC0\u0EC1\u0EC2\u0EC3\u0EC4\uAAB5\uAAB6\uAAB9\uAABB\uAABC]*(?:[\u1100-\u115F\uA960-\uA97C]+|([\u1100-\u115F\uA960-\uA97C]*((?:[[\u1160-\u11A2\uD7B0-\uD7C6][\uAC00\uAC1C\uAC38]][\u1160-\u11A2\uD7B0-\uD7C6]*|[\uAC01\uAC02\uAC03\uAC04])[\u11A8-\u11F9\uD7CB-\uD7FB]*))|[\u11A8-\u11F9\uD7CB-\uD7FB]+|[^[\p{Zl}\p{Zp}\p{Cc}\p{Cf}&&[^\u000D\u000A\u200C\u200D]]\u000D\u000A])[[\p{Mn}\p{Me}\u200C\u200D\u0488\u0489\u20DD\u20DE\u20DF\u20E0\u20E2\u20E3\u20E4\uA670\uA671\uA672\uFF9E\uFF9F][\p{Mc}\u0E30\u0E32\u0E33\u0E45\u0EB0\u0EB2\u0EB3]]*)|(?s:.))

yang di Java Anda akan menulis sebagai:

String extended_grapheme_cluster = "(?:(?:\\u000D\\u000A)|(?:[\\u0E40\\u0E41\\u0E42\\u0E43\\u0E44\\u0EC0\\u0EC1\\u0EC2\\u0EC3\\u0EC4\\uAAB5\\uAAB6\\uAAB9\\uAABB\\uAABC]*(?:[\\u1100-\\u115F\\uA960-\\uA97C]+|([\\u1100-\\u115F\\uA960-\\uA97C]*((?:[[\\u1160-\\u11A2\\uD7B0-\\uD7C6][\\uAC00\\uAC1C\\uAC38]][\\u1160-\\u11A2\\uD7B0-\\uD7C6]*|[\\uAC01\\uAC02\\uAC03\\uAC04])[\\u11A8-\\u11F9\\uD7CB-\\uD7FB]*))|[\\u11A8-\\u11F9\\uD7CB-\\uD7FB]+|[^[\\p{Zl}\\p{Zp}\\p{Cc}\\p{Cf}&&[^\\u000D\\u000A\\u200C\\u200D]]\\u000D\\u000A])[[\\p{Mn}\\p{Me}\\u200C\\u200D\\u0488\\u0489\\u20DD\\u20DE\\u20DF\\u20E0\\u20E2\\u20E3\\u20E4\\uA670\\uA671\\uA672\\uFF9E\\uFF9F][\\p{Mc}\\u0E30\\u0E32\\u0E33\\u0E45\\u0EB0\\u0EB2\\u0EB3]]*)|(?s:.))";

¡Tschüß!

tchrist
sumber
10
Ini luar biasa. Terima kasih banyak.
Tim Pietzcker
9
Ya Tuhan, itu jawaban yang mencerahkan. Saya hanya tidak mendapatkan referensi Jon Skeet. Apa hubungannya dengan ini?
BalusC
12
@BalusC: Ini adalah referensi untuk Jon sebelumnya yang mengatakan dia akan membiarkan saya menjawab pertanyaan itu. Tapi tolong, jangan berhenti tdi @tchrist. Mungkin sampai ke kepalaku. :)
tchrist
3
Pernahkah Anda berpikir untuk menambahkan ini ke OpenJDK?
Martijn Verburg
2
@ Martijn: Saya tidak, tidak; Saya tidak tahu itu "terbuka". :) Tapi saya telah berpikir untuk merilisnya dalam arti yang lebih formal; orang lain di departemen saya ingin menyelesaikannya (dengan semacam lisensi sumber terbuka, mungkin BSD atau ASL). Saya mungkin akan mengubah API dari apa yang ada di prototipe alfa ini, membersihkan kode, dll. Tapi itu sangat membantu kami , dan kami pikir itu akan membantu orang lain juga. Saya benar-benar berharap Sun akan melakukan sesuatu tentang perpustakaan mereka, tetapi Oracle tidak menginspirasi kepercayaan diri.
tchrist
15

Sangat disayangkan itu \wtidak berhasil. Solusi yang diusulkan \p{Alpha}juga tidak berhasil untuk saya.

Tampaknya [\p{L}]menangkap semua huruf Unicode. Jadi padanan Unicode \wseharusnya [\p{L}\p{Digit}_].

musiKk
sumber
Tapi \wjuga cocok dengan angka dan banyak lagi. Saya pikir hanya untuk surat, \p{L}akan berhasil.
Tim Pietzcker
Kamu benar. \p{L}cukup. Saya juga berpikir bahwa masalahnya hanya huruf. [\p{L}\p{Digit}_]harus menangkap semua karakter alfanumerik termasuk garis bawah.
musiKk
@MusicKk: Lihat jawaban saya untuk solusi lengkap yang memungkinkan Anda menulis pola Anda secara normal, tetapi kemudian meneruskannya melalui fungsi yang mengoreksi kekosongan Java yang menganga sehingga berfungsi dengan baik di Unicode.
tchrist
Tidak, \wUnicode didefinisikan sebagai lebih luas dari sekedar \pLdan digit ASCII, dari semua hal konyol. Anda harus menulis [\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]]jika Anda menginginkan Unicode-aware \wuntuk Java - atau Anda bisa menggunakan unicode_charclassfungsi saya dari sini . Maaf!
tchrist
1
@ Tim, ya, karena surat \pLmemang berfungsi (Anda tidak perlu menggunakan alat peraga satu huruf). Namun, Anda jarang menginginkannya, karena Anda harus lebih berhati-hati agar pasangan Anda tidak mendapatkan jawaban yang berbeda hanya karena data Anda dalam Unicode Normalization Form D (alias NFD, yang berarti dekomposisi kanonik ) versus berada di NFC (NFD diikuti oleh kanonik komposisi ). Contohnya adalah titik kode U + E9 ( "é") adalah \pLdalam bentuk NFC, tetapi bentuk NFD-nya menjadi U + 65,301, jadi cocok \pL\pM. Anda bisa agak mendapatkan sekitar ini dengan \X: (?:(?=\pL)\X), tapi Anda harus versi saya bahwa untuk Java. :(
tchrist
7

Di Jawa, \wdan \dtidak sadar-Unicode; mereka hanya cocok dengan karakter ASCII, [A-Za-z0-9_]dan[0-9] . Hal yang sama berlaku untuk \p{Alpha}dan teman-teman ("kelas karakter" POSIX yang menjadi dasar mereka seharusnya peka terhadap lokal, tetapi di Jawa mereka hanya cocok dengan karakter ASCII). Jika Anda ingin mencocokkan "karakter kata" Unicode Anda harus mengejanya, misalnya [\pL\p{Mn}\p{Nd}\p{Pc}], untuk huruf, pengubah non-spasi (aksen), angka desimal, dan tanda baca penghubung.

Namun, Jawa \b adalah Unicode-savvy; ia menggunakan Character.isLetterOrDigit(ch)dan memeriksa huruf beraksen juga, tetapi satu-satunya karakter "penghubung tanda baca" yang dikenali adalah garis bawah. EDIT: ketika saya mencoba kode sampel Anda, itu dicetak ""dan élève"sebagaimana mestinya ( lihat di ideone.com ).

Alan Moore
sumber
Maaf, Alan, tetapi Anda benar-benar tidak bisa mengatakan bahwa Java \bmengerti Unicode. Itu membuat banyak sekali kesalahan. "\u2163=",, "\u24e7="dan "\u0301="semua gagal mencocokkan pola "\\b="di Jawa, tetapi seharusnya - seperti yang perl -le 'print /\b=/ || 0 for "\x{2163}=", "\x{24e7}=", "\x{301}="'diungkapkan. Namun, jika (dan hanya jika) Anda menukar batas kata versi saya alih-alih yang asli \bdi Java, maka semua itu juga berfungsi di Java.
tchrist
@tchrist: Saya tidak mengomentari \bkebenarannya, hanya menunjukkan bahwa ini beroperasi pada karakter Unicode (seperti yang diterapkan di Java), tidak hanya seperti ASCII \wdan teman-teman. Namun, ini berfungsi dengan benar sehubungan dengan \u0301kapan karakter itu dipasangkan dengan karakter dasar, seperti pada e\u0301=. Dan saya tidak yakin bahwa Java salah dalam hal ini. Bagaimana tanda kombinasi dianggap sebagai karakter kata kecuali itu adalah bagian dari cluster grafem dengan sebuah huruf?
Alan Moore
3
@Alan, ini adalah sesuatu yang dibersihkan ketika Unicode mengklarifikasi cluster grafem dengan membahas cluster grafem yang diperpanjang vs lama. Definisi lama dari cluster grafem, di mana \Xsingkatan dari non-mark diikuti dengan sejumlah tanda, bermasalah, karena Anda harus dapat menggambarkan semua file sebagai cocok /^(\X*\R)*\R?$/, tetapi Anda tidak bisa jika Anda memiliki \pMdi awal file, atau bahkan baris. Jadi mereka telah mengembangkannya agar selalu cocok dengan setidaknya satu karakter. Itu selalu terjadi, tapi sekarang pola di atas berhasil. [… Lanjutan…]
tchrist
2
@Alan, itu lebih berbahaya daripada baik karena native Java \bsebagian peka terhadap Unicode. Pertimbangkan untuk mencocokkan benang "élève"dengan pola \b(\w+)\b. Lihat masalahnya?
tchrist
1
@tchrist: Ya, tanpa batas kata, \w+menemukan dua kecocokan: ldan ve, yang sudah cukup buruk. Tetapi dengan batasan kata itu tidak menemukan apa-apa, karena \bmengenali édan èsebagai karakter kata. Minimal, \bdan \wharus setuju tentang apa itu karakter kata dan apa yang bukan.
Alan Moore