regex - lapanie znakow > \uFFFF

0

Witam. Mam taki problem - mam napisac regex ktory potrafi sie obchodzic ze znakami powyzej \uFFFF, ponizej kod (Groovy, ale latwo przeniesc):

import java.util.regex.*

def p = Pattern.compile('[\u10000 -\uEFFFF]+')
println p.pattern() // prints [က0-F]+
println p.matcher('0').matches() // true
println p.matcher('F').matches() // true
println p.matcher('abc').matches() // true

Wyniki sa zle, poniewaz oczekuje ze wszedzie bedzie false, bo przedzial ktory chce osiagnac nie zawiera zadnego ze znakow '0', 'F', 'a', 'b', 'c'. Problem wynika z tego, ze regex ktory jest tworzony to: \u1000 LUB 0-\uEFFF LUB F (jak widac w println p.pattern(), gdzie te kratki to znaki \u1000 i \uEFFF) poniewaz Java \u pozwala tylko na 4 znaki hex, a tu jest 5, i te 5 sa traktowane doslownie. Jak utworzyc w Javie regexa o ktory mi chodzi? Czy nie da sie?

0

Ok, Java 7 wprowadza zmiany w zakresie Unicode, miedzy innymi nowe switche w java.util.regex.Pattern, np.:
\x{h...h} The character with hexadecimal value 0xh...h (Character.MIN_CODE_POINT <= 0xh...h <= Character.MAX_CODE_POINT)

czyli mozna zrobic \x{10000}-\x{EFFFF} i dziala.

Co z Java 6? Nie da sie, czy jest to po prostu trudniejsze?

0

Ok, w Javie 6 rowniez dziala, trzeba przedzialy zakodowac w surogaty UTF-16 tak jak opisuje algo opisany tutaj: http://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B10000_to_U.2B10FFFF (java wewnetrznie uzywa UTF=16, tylko znaki z BMP sa reprezentowane bezproblemowo, z reszta trzeba sie babrac). Naiwna implementacja:

def chars(cp) {
    assert cp in 0x10000..0x10FFFF
    def s = Integer.toBinaryString(cp - 0x10000)
    assert s.size() <= 20
    s = s.padLeft(20, '0')
    def lead = Integer.parseInt(s[0..<10], 2) + 0xD800
    def trail = Integer.parseInt(s[10..<20], 2) + 0xDC00
    println "cp: ${Integer.toHexString(cp)}, chars: \\u${Integer.toHexString(lead)}\\u${Integer.toHexString(trail)}"
}

chars(0x10000) // cp: 10000, chars: \ud800\udc00
chars(0x10FFFF) // cp: 10ffff, chars: \udbff\udfff
chars(0xEFFFF) // cp: effff, chars: \udb7f\udfff

A tutaj jeszcze kod z pierwszego posta, tym razem dzialajacy poprawnie, definiujacy poprawnie przedzialy:

import java.util.regex.*

def p = ~'[\ud800\udc00-\udb7f\udfff]+'
println p // prints [?-?]+
assert !('0' ==~ p)
assert !('F' ==~ p)
assert !('abc' ==~ p)
assert new String(0x10000 as int[], 0, 1) ==~ p
assert new String(0x2FFFF as int[], 0, 1) ==~ p
assert new String(0xEFFFF as int[], 0, 1) ==~ p
assert !(new String(0xF0000 as int[], 0, 1) ==~ p)
0

Admina / moda prosilbym aby zaznaczyl ostatnio post jako rozwiazanie, moze sie komus przydac.

1 użytkowników online, w tym zalogowanych: 0, gości: 1