SORU
29 Kasım 2010, PAZARTESİ


\W ve \b benzerleri Java düzenli ifadeler Unicode?

Birçok modern düzenli uygulamaları \w karakter sınıfı steno olarak yorumlamak "herhangi bir harf, rakam veya noktalama bağlanma" (genellikle: alt çizgi). Bu şekilde, \w gibi bir düzenli ifadehello, élève, GOÄ_432 ya gefräßig gibi kelimeler ile eşleşir.

Ne yazık ki, Java değil. Java, \w [A-Za-z0-9_] ile sınırlıdır. Bu yukarıda olanlar gibi kelimeler eşleşen zor, diğer sorunlar arasında yapar.

Ayrıca \b sözcük ayırıcı olmamalı yerlerde eşleşen görüntülenir.

Bir doğru eşdeğer ne olabilir .AĞ gibi, Unicode ile uyumlu \w \b Java? Diğer ihtiyacım var "" onları Unicode ile uyumlu hale getirmek için mi? yeniden yazma kısayolları

CEVAP
29 Kasım 2010, PAZARTESİ


Kaynak kodu

Ben aşağıda tekrar görüşmek fonksiyonları için kaynak koduis available here.

Java 7 Update

JDK7 için güneş Pattern updated sınıf her şeyi doğru iş yapan harika yeni bir bayrak UNICODE_CHARACTER_CLASS sahiptir. Bir gömülebilir olarak kullanılabilir (?U) desen içinde, String sınıfın ambalajı ile de kullanabilirsiniz. Ayrıca diğer özellikler için düzeltilmiş tanımları da spor. Şimdi Unicode Standardı, RL1.2 102 *hem parçalarıUTS#18: Unicode Düzenli İfadeler. Bu heyecan verici ve dramatik bir iyileştirme ve geliştirme ekibi bu önemli çaba için takdir edilmelidir.


Java Düzenli ifade Unicode Sorunları var

Sorun Java yukarıdaki diyagram bu Perl 1.0 charclass kaçtığı bir anlam \w, \b, \s, \d ve onların tamamlar — Java genişletilmiş çalışma ile Unicode. Bunlar arasında tek başına \b belirli bir dile özgü semantiği sahiptir, ama bu Unicode line-break properties ** 104 \w, ne de ne de göster.

Ayrıca, Java POSIX Özellikleri Bu şekilde erişilir:

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}

Bu Alpha, Lower Space gibi şeyler yapmak anlamına gelir, çünkü bu gerçek bir felaket olurdeğilJava Unicode göster Alphabetic, Lowercase Whitespace özellikleri. Bu exceeedingly can sıkıcı bir durum. Java Unicode özelliği desteğikesinlikle antemillennial, yani son on yılda ortaya çıkmıştır Unicode özelliği destekler.

Boşluk hakkında konuşamamak düzgün süper can sıkıcı bir durum. Aşağıdaki tablo göz önünde bulundurun. Bu kod noktaları her biri için, J-sonuç Her iki sütun var Java ve P-sonuçlar Perl veya başka bir sütun / temel düzenli ifade motoru: bir

             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  -

Bunu gördün mü?

Bu Java boşluk sonuçlar hemen hemen her bir Unicode göre yanlış. Birgerçekten büyük bir sorun.Java sadece berbat, “yanlış” mevcut uygulamaya ve ayrıca Unicode göre. göre cevaplar veriyor Artı bile gerçek Unicode özellikleri erişim sağlar Java yok! Aslında, Java desteklemiyorherhangi birözelliği bu boşluk Unicode karşılık gelir.


Tüm Bu Sorunların Çözümü ve Daha fazlası

Bu ve diğer birçok ilgili sorunları ile başa çıkmak için, dün bu 14 charclass kaçar yeniden yazar, desen bir dize yazmak için bir Java fonksiyonu yazdım:

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

şey ile değiştirilmesi, aslında öngörülebilir ve tutarlı bir şekilde Unicode maç için çalışıyoruz. Sadece hack tek oturum, alfa prototip, ama tamamen işlevseldir.

Kısa öykü benim kod aşağıdaki gibi, bu 14 yeniden yazar

\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*)

Bazı şeyleri göz önünde bulundurun

  • Bu gibi 106 ** \X tanımı için kullanıreski küme graphemedeğil ., ^em>genişletilmiş grapheme kümeikincisi biraz daha karmaşık olduğu gibi., Perl kendisi şimdi meraklısı sürümünü kullanır, ama eski sürümü hala en yaygın durumlar için mükemmel çalışır.DÜZENLEME:Altındaki Eki bakın.

  • Ne \d niyetiniz bağlıdır, ancak varsayılan Uniode tanımıdır. İnsanlar her zaman istememek \p{Nd} ama bazen [0-9] \pN ya da görebiliyorum.

  • İki sınır tanımları, \b* *49, özellikle \w tanımını kullanmak için yazılmış.

  • \w bu tanım olanları daire içine alınmış parenned harfleri kapmak değil sadece, çünkü fazlasıyla geniş. Other_Alphabetic Unicode özelliği yapabileceğinin en iyisi bu yüzden JDK7 kadar müsait değil.


Sınırları Keşfetmek

Sınırları hiç Larry Wall ilk geri Perl 1.0 için onlar hakkında konuşuyor \b ve \B sözdizimi 1987 yılında icat beri bir sorun olmuştur. \b \B hem de nasıl çalıştığını anlamanın anahtarı onlar hakkında iki yaygın mitleri yok

  1. Onlarbakıyorum sadece\w sözcük karakteri içinaslasözcük olmayan karakter için.
  2. Özellikle dize kenarına bakın.

\b sınır anlamına gelir:

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

Ve o mükemmel bir delikanlı olarak tanımlanır:

  • aşağıdaki kelime60**.
  • önündeki kelime(?=\w).
  • kelime takip etmiyor(?<!\w).
  • word önüne gelmez(?!\w).

Bu nedenle, bu yana IF-THEN kodlanmış bir and ed-birlikte AB yukarıdaki diyagram, bir or X|Y çünkü and yüksek öncelik daha or, yani sadece AB|CD. Bir sınır anlamına gelir \b her ile güvenli bir şekilde değiştirilir, böylece:

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

\w uygun şekilde belirlenmeli.

(A C bileşenleri zıt olan bu size garip gelebilir. Mükemmel bir dünyada, AB|D ama ben bir süre için bir Unicode özellikleri karşılıklı dışlama çelişkiler peşinde olduğumu yazmak gerekirdüşünüyorumBen baktım, ama sınır çift koşulu diye bıraktım. Ayrıca bu ekstra fikirler daha sonra alırsanız daha genişletilebilir yapar.)

\B olmayan sınırları, mantığı

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

\B tüm örnekleri ile değiştirilmesi için izin:

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

Bu gerçekten \b \B böyle davranır. Onlar için eşdeğer desenleri vardır

  • \b ((IF)THEN|ELSE) yapı kullanıyor (?(?<=\w)(?!\w)|(?=\w))
  • \B ((IF)THEN|ELSE) yapı kullanıyor (?(?=\w)(?<=\w)|(?<!\w))

Ama sadece AB|CD sürümleri ile özellikle Java gibi düzenli bir dil şartlı desenler eksikliği varsa, gayet iyi. ☹

Zaten sınırları denetler 110,385,408 başına çalıştırmak maçı, bir düzine farklı veri yapılandırmaları göre çalışacak ... ... ki: bir test paketi ile üç eşdeğer tanımları kullanarak davranışlarını teyit ettim

     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)

Ancak, insanlar genellikle sınır farklı bir tür istiyorum. Boşluk ve-kenar dize farkında olan bir şeyi istiyorlar:

  • sol kenar(?:(?<=^)|(?<=\s)) gibi
  • sağ kenar(?=$|\s) gibi

Java ile Java sabitleme

my other answer mesajınız kodu bu ve pek çok başka kolaylıklar sağlar. Bu doğal dil kelimeler, tire, tire ve kesme için tanımlar, artı biraz daha fazlasını içerir.

Ayrıca aptalca mantıksal kod noktaları, UTF-16 Unicode karakterleri Suretler değil belirlemenizi sağlar.Sabit ne kadar önemli olduğunu bırakılan!Ve bu sadece dize genişleme için.

Düzenli ifade için charclass Java yukarıdaki diyagram içinde charclass kılan değiştirmenihayetUnicode üzerinde çalışmakve doğru çalışmasıyakalathe full source from here.İstediğin gibi elbette yapabilir. Eğer bu düzeltmeleri yaparsanız, bunu duymak isterdim ama gerek yok. Oldukça kısa. Ana normal ifade yeniden işlev yürek basittir:

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;

Her neyse, bu kodu sadece bir alfa sürümü, bir hafta sonu girdim falan. Bu şekilde kalmayacaktır.

Beta için niyetindeyim:

  • birlikte kod tekrarından kat

  • düzenli kaçar artırmada karşı daha net bir arayüz atlanmaması dize kaçar ile ilgili sağlar

  • \d genişleme bazı esneklik sağlar, ve belki de \b

  • ve Desen etrafında dönen arıyorum tanıtıcı uygun yöntem bulunur.derleme ya da Dize.ya da sizin için maçlar falan

Üretim serbest bırakılması için, javadoc ve JUnit test suite olmalı. Benim gigatester dahil olabilirim, ama JUnit testleri olarak yazılı değil.


Ek

İyi haber ve kötü haberlerim var.

İyi haber, şimdi de varçokbir yakınsama yakıngenişletilmiş grapheme kümebir kullanım için geliştirildi 97*.

Kötü haber dünyasının bu tip olduğunu

(?:(?:\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:.))

yazmak gibi olurdu hangi:

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üß!

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Day9TV

    Day9TV

    22 NİSAN 2010
  • ibebrent

    ibebrent

    23 Temmuz 2007
  • LimeFire

    LimeFire

    2 ŞUBAT 2012