[:alpha:] a polskie znaki pod linuxem

Hej
Problem jak w temacie,
załóżmy, że mamy programik typu:

def f(a)
wyr=Regexp.new(’^[[:alpha:]]$’)
if a=~wyr
“ok”
else
“nie pasuje”
end
end

while linia=STDIN.gets
puts f(linia.chomp)
end

przy wpisywaniu “zwykłych literek” jest ok, polskie nie przechodzą,
ale jeśli wciągnę to do irb (tzn. tego def-a samego) to zarówno f(‘a’) i f(‘ą’) są ok

Czy ktoś mógłby mi pomóc?
Pracuję pod iso88592 (muszę niestety) i potrzebowałbym, żeby wyrażenia regularne przechwytywały też polskie znaki, a napotkałem właśnie taki problem. Mam ustawione locale na to iso, więc teoretycznie nie powinno być problemu (no i irb też tak to widzi)… Może jakoś trzeba włączyć to iso w programie (coś typu use locale z Perla)??
Będę wdzięczny za pomoc…

IMHO [[:alpha:]] powinno zmatchować jedynie znaki z zakresu [a-zA-Z] bez żadnych ogonków, umlautów itp. Być może w twojej konsoli iso-8859-2 litera ą generuje kod z tego zakresu ?

Na Twoim miejscu dodałbym znaki z ogonkami do tego regexp’a (w iso-8859-2)

Pamietam ze jest chyba jakas flaga ktora umozliwa przeszukiwanie wszystkich znakow alfabetycznych w zakresie a-z

Perl własnie, w przypadku użycia locale, potrafił łapać polskie litery poprawnie poprzez takie klasy znaków. Właśnie po to wymyślono takie klasy, by można było operować na pewnej abstrakcji (cyfry, litery małe, duże, drukowalne znaki). Ciężko mi coś o tym powiedzieć (szukałem ale nic nie znalazłem). Co ciekawe takie coś działa:

[code=irb]>> r1 = /^\w+/
=> w

r1 = /^\w+$/
=> w

r2 = /^\w+$/u
=> wu

r1.match(“ą”)
=> nil

r2.match(“ą”)
=> #MatchData:0x2b5c6dfbf2a8[/code]
Z tego co widzę to w 1.9 nasza klasa znakowa alpha działa już dobrze:

[code=ruby]def f(a)
#wyr=Regexp.new(’^[[:alpha:]]$’, nil, ‘U’)
wyr = /^[[:alpha:]]+/u
if a=~wyr
“ok”
else
“nie pasuje”
end
end

puts f(“a”)
puts f(“ą”)[/code]

[quote]$ ruby -v
ruby 1.8.6 (2007-06-07 patchlevel 36) [x86_64-linux]
$ ruby test.rb
ok
nie pasuje

$ ruby-trunk -v
ruby 1.9.0 (2007-11-05 patchlevel 0) [x86_64-linux]
$ ruby-trunk test.rb
ok
ok[/quote]

[quote=hosiawak]IMHO [[:alpha:]] powinno zmatchować jedynie znaki z zakresu [a-zA-Z] bez żadnych ogonków, umlautów itp. Być może w twojej konsoli iso-8859-2 litera ą generuje kod z tego zakresu ?

Na Twoim miejscu dodałbym znaki z ogonkami do tego regexp’a (w iso-8859-2)[/quote]
Rozumiem, że chodzi Ci o coś typu:
wyr=Regexp.new(’^([a-zA-ZąćęłńóśźżĄĆĘŁŃÓŚŹŻ]+)$’)
tylko tego właśnie chciałem uniknąć przez użycie [[:alpha:]] (no bo niby czemu pod irb-em widzi, że
[[:alpha:]] to też polski znak a pod ruby-m już nie?)

[quote=radarek]Co ciekawe takie coś działa:

[code=irb]>> r1 = /^\w+/
=> w

r1 = /^\w+$/
=> w

r2 = /^\w+$/u
=> wu

r1.match(“ą”)
=> nil

r2.match(“ą”)
=> #MatchData:0x2b5c6dfbf2a8[/code]
[/quote]
Mi niestety nie bardzo działa :frowning: A mógłbyś wyjaśnić zastosowanie tego ‘u’ po wyrażeniu regularnym?

[quote=radarek]$ ruby -v
ruby 1.8.6 (2007-06-07 patchlevel 36) [x86_64-linux]
$ ruby test.rb
ok
nie pasuje

$ ruby-trunk -v
ruby 1.9.0 (2007-11-05 patchlevel 0) [x86_64-linux]
$ ruby-trunk test.rb
ok
ok[/quote]
Poszedłem za radą, zainstalowałem wersje 1.9, ale też w drugim przypadku dostaję “nie pasuje”, do tego jako ciekawostka: w irb1.8 to działało, ale w irb1.9 też jest już “nie pasuje”

Nie rozumiem tego, że raz to wyrażenie działa, a raz nie działa…

Ten przełącznik ‘u’ mówi że wyrażenie regularne jest w utf (a także to z czym będziesz porównywać). Żeby działało musisz oczywiście takie kodowanie zastosować (np ustawiając takie w edytorze).

Rozszerzając komentarz Radarka - zacznijmy od tego, ze Ruby 1.8 nie wbudowanego wsparcia dla Unicode. W szczególności dotyczy to właśnie wyrażeń regularnych, a to co można uzyskać dzięki fladze ‘u’, nie obejmuje właśnie takich przypadków jak [[:alpha:]]. Dotyczy to również sortowania znaków - Ruby 1.8 “nie wie”, że ą leży między a i b.

Druga kwestia to testowanie dopasowania. O ile w innych przypadkach irb świetnie nadaj się do testowania różnych nieznanych nam własności języka, o tyle w tym przypadku zdecydowania odradzam. Chodzi o to, że jeśli masz pliki źródłowe w utf8 (zakładam, że takie stosujesz na swojej stronie interentowej) to w irb też powinieneś wszystko testować jako utf8. Problem jest taki, że zarówno pod Windows jak i pod Linuxem większość terminali ma ustawione kodowanie na win-cp/iso-8859-2. Więc działania wyrażeń reg. może się różnić w obu wypadkach.

Dlatego najlepiej w tym wypadku pisać sobie kod i dane testowe w plikach i na nich to testować (można np. je wczytać do irb, ale w tym wypadku chyba nie ma to sensu). Najlepiej do ich edycji użyć jakiegoś edytora, w którym możemy określić kodowanie przy wczytywaniu jak i zapisywaniu pliku. Ja polecam yudit. Nie dość, że możesz wybrać każde kodowanie dostępne pod słońcem, to możesz również pisać np. w innym kierunku tekst w jidisz, albo wprowadzać polskie znaki, w systemie, w którym dostępny jest tylko zestaw znaków iso-8859-1. Zdecydowania polecam.

[quote=apohllo]Rozszerzając komentarz Radarka - zacznijmy od tego, ze Ruby 1.8 nie wbudowanego wsparcia dla Unicode. W szczególności dotyczy to właśnie wyrażeń regularnych, a to co można uzyskać dzięki fladze ‘u’, nie obejmuje właśnie takich przypadków jak [[:alpha:]]. Dotyczy to również sortowania znaków - Ruby 1.8 “nie wie”, że ą leży między a i b.

Chodzi o to, że jeśli masz pliki źródłowe w utf8 (zakładam, że takie stosujesz na swojej stronie interentowej) to w irb też powinieneś wszystko testować jako utf8.[/quote]
hmmm… no nie do końca tak jest. Mam ustawione w systemie locale na iso8859-2, a także wszystkie pliki, z których korzystam mają ustawione takie kodowanie. Nigdzie nie używam unicode/utf…

A co jeszcze ciekawsze, drugi programik, w którym właśnie takie [:alpha:] zastosowałem, działa dobrze (po zamianie z \w, które właśnie taki sam efekt dawało, czyli nie łapało polskich liter). Kwestia jest taka, że on dziedziczy nie z mojej własnej klasy, więc nie wiem co on tam po drodze z tymi łańcuchami robi… Dlatego się zdziwiłem, że jeśli pod irb-em również to działa, to tutaj są takie kłopoty…

Myślę, że problem sprowadza się do tego, czy jest w Ruby-m coś w stylu perlowego: use locale. Bo wiadomo, że klasa [[:alpha:]] powinna działać niezależnie od kodowania i łapać znaki (to \w jest zastępnikiem [a-zA-Z], więc nie będzie łapać polskich liter). Chodzi tylko o to jak “powiedzieć” programowi, żeby korzystał z lokalnego zbioru znaków (przecież jeśli używam locale: iso a nie utf, to system wie jak wyglądają polskie znaki i np. w konsoli też nie wyświetla krzaczków)

To, że nie wyświetlają się krzaczki jest zupełnie (albo prawie zupełnie) niezależne od tego co z literkami dzieje się w wyrażeniach regularnych, etc. Iso-8859-2 podobnie jak utf8 to sposób kodowania znaków, czyli mówiąc obrazowo, że bajtowi o wartości 65 w jakimś łańcuchu znaków odpowiada litera ‘A’ (właściwie: znak ‘A’ na ekranie’). Kodowanie jednak w żaden sposób nie określa, które znaki są literami, a które nie. Operatory takie jak \w najczęściej sprawdzają tylko czy kod znaku należy do odpowiedniego przedziału wartości. Więc locale w tym wypadku określa tylko czcionkę, która ma “właściwy” zestaw znaków dla określonych bajtów (właściwie: wariant czcionki) oraz (chyba) wartości jakie przyporządkowane są poszczególnym klawiszom i ich kombinacjom (ale to, jak wiadomo, można sobie zmienić).

Kodowanie znaków jednak nie określa w żaden sposób, czy dany znak jest literą, czy cyfrą oraz kolejności w jakiej znaki występują. Z tego co wiem, to jest ustalone chyba tylko w standardzie Unicode, który również znakom przyporządkowuje liczby, ale w inny sposób niż kodowanie. Nie ma tutaj mowy bezpośrednio o bitach, czy bajtach - po prostu każdy znak ma przyporządkowaną inną liczbę. Poza tym tych znaków jest znacznie więcej, niż zmieściłoby się w jednym bajcie (jest ich kilkadziesiąt tysięcy). Dla unicode określono mapowania (jednym z nich jest utf8), które określają, że danemu bajtowi lub ciągowi bajtów odpowiada określony numer znaku Unicode.

Co prawda niektóre programy (np. bazy danych) w zestawach (np. w MySQL atrybut: collation) mają zaszyte informacje o tym, że w ISO-8859-2 coś jest literą (również ą). Nie znam jednak standardu, który by to definiował. Z tego co wiem standard POSIX, który definiuje klasy znaków takie jak [:alpha:] bazuje wyłącznie na Unicode (pośrednio tak jest napisana w jednej książce, którą mam pod ręką, więc nie dają za to głowy).

Dlatego wszędzie gdzie stosujemy jakieś bardziej zaawansowane operacje na znakach najlepiej stosować Unicode. Inna sprawa, że Ruby póki co ma go kiepsko zaimplementowane.
Spróbuj skorzystać z JRuby, którego Unicode opiera się na Javowej implemntacji (która uchodzi za najbardziej kompletną). Wtedy wszystko powinno śmigać (oczywiście o ile używasz Unicode np. z utf8).

Acha - jeszcze jedna uwaga - jak testujesz tego rodzaju problemy, to zawsze sprawdzaj dla wszystkich znaków. Czasem zdarza się, że błędna implementacja potraktuje Ci ‘ą’ jako znak, a ‘ę’ nie :confused: (Już nie raz się na tym przejechałem).