Iconv - różnica między irb a moim skryptem

Witam,

mam skrypcik:

require ‘iconv’
s = ‘ąęśćńź’
puts Iconv.iconv(‘ASCII//TRANSLIT’, ‘UTF-8’, s)

Oczekuję, że wypluje “aescnz”.

Niestety, uruchomiony jako “ruby mojskrypt.rb” wypluwa “???” - Iconv nie poradził sobie z transliteracją.

Patent polega na tym, że gdy uruchomię irb i wydam te same komendy, to działa OK. To samo dotyczy konsoli rails.

Podejrzewam, że ww. narzędzia ładują jakiś moduł bądź ustawiają jakieś zmienne niezbędne do konwersji. Gdzie tego szukać?

[code]$ irb

require ‘iconv’
=> true

s = ‘ąęśćńź’
=> “\304\205\304\231\305\233\304\207\305\204\305\272”

puts Iconv.iconv(‘ASCII//TRANSLIT’, ‘UTF-8’, s)
ae’s’c’n’z
=> nil

exit
$ ruby test.rb
ae’s’c’n’z[/code]
Sprawdź, czy Twój edytor zapisuje plik w UTF-8. Jestem prawie pewien, że w tym tkwi ten problem.

Ja to robię mniej więcej tak jak opisywałem w tym poście: http://blog.drogomir.com/articles/2008/01/12/przyjazne-adresy-w-ruby-on-rails

Ew. sprawdz czy Twoj klient SSH (np.: putty) ma ustawione poprawne kodowanie (a dokladnie translacje).

Pozdrawiam
Pawel

To na 100% nie kodowanie w ssh.
Sprawdziłem u siebie, Debian Lenny (testing):

[code]underley@uriel:~:$ cat x.rb
require ‘iconv’

s = “\304\205\304\231\305\233\304\207\305\204\305\272”
puts Iconv.iconv(‘ASCII//TRANSLIT’, ‘UTF-8’, s)
underley@uriel:~:$ ruby x.rb
???
underley@uriel:~:$ ruby x.rb | hexdump
0000000 3f3f 3f3f 3f3f 000a
0000007
underley@uriel:~:$ irb
irb(main):001:0> require ‘iconv’
=> true
irb(main):002:0>
irb(main):003:0* s = “\304\205\304\231\305\233\304\207\305\204\305\272”
=> “\304\205\304\231\305\233\304\207\305\204\305\272”
irb(main):004:0> puts Iconv.iconv(‘ASCII//TRANSLIT’, ‘UTF-8’, s)
aescnz
=> nil[/code]

Ej no, bez przesady z tym kodowaniem i SSH. To nie jest kodowanie SSH. Zresztą obie operacje wykonuję w tej samej sesji więc nawet jak mam złą translację to efekty powinny być identyczne.

Spróbuję z http://www.jroller.com/obie/entry/fix_that_tranny_add_to

Czy to nie jest bug jakiś?

OK, ww. rozwiązania są nie do zaakceptowania.

Unicode.normalize_KD(‘ęóąśłżźćń’).unpack(‘U*’).select{ |cp| cp < 127 }.pack(‘U*’) daje efekt “eoaszzcn” (nie ma literki “l”)

Rozwiązanie oparte o tablicę translacji też nie jest OK - robię system, który może pracować w wielu językach i nie mogę zakładać, że ktoś mi nie wpisze czegoś dziwnego.

Najlepiej by było odpalić iconv ale jak widać nie działa :frowning:

Tym niemniej dzięki za pomoc. Gdyby ktoś się dowiedział, co jest nie tak z tym iconv to proszę o posta :slight_smile:

Mam ten sam problem co Ty, pardon.

Można to obejść używając iconv bezpośrednio (nie poprzez API Rubiego):

[code]echo ąęóć | LC_CTYPE=en_US iconv -f utf8 -t ascii//translit

-> ???[/code]

[code]echo ąęóć | LC_CTYPE=pl_PL iconv -f utf8 -t ascii//translit

-> aeoc[/code]
Ważne jest ustawienie zmiennej środowiskowej LC_CTYPE na pl_PL.
Niestety nie ma wpływu na Iconv w Rubim. Nie działa też ustawienie ENV[‘LC_CTYPE’]
Zawsze możesz wywołać iconv bezpośrednio. Poszukajo tym LC_CTYPE, może coś znajdziesz.

Hmm nie wiem czy to tędy droga. Potrzebuję kod, który mi wytnie po prostu wszystkie ogonki, bez względu na ustawienia środowiska. To, że mój serwer pracuje w jakimś LC, czy coś wymuszę, to nie znaczy, że można na tym polegać - mogę mieć w systemie gościa z francji, który wpisuje dane po węgiersku i to musi działać.

Rzuciłem pytanie na comp.lang.ruby, zobaczymy czy ktoś odpowie. Jak tak, wkleję.

Dostałem taką odpowiedź…

[quote]Shot (Piotr Szotkowski) wrote:

You need to tell Ruby you’re talking in UTF-8 to it in the first place.
I have -Ku in my $RUBYOPT environmental variable (you can also simply
$KCODE = ‘u’
in your Ruby code) and I get the below:

Sad to say but this is a problem that we have spent many hours trying to
fix. By all means, try fiddling with the the KCODE variables. You may
also want to experiment with setting the environment LANG and LC
variables, and importing parts of irb. Good luck with that.

When that doesn’t work you have two (maybe three) options.

First you can install Ruby-GNOME2, which has the function
GLib.convert/3. That works properly on our system even though Iconv
doesn’t:

require ‘gtk2’
GLib.convert(“ąćęłńóśźż”, “ASCII//translit”, “UTF-8”)

Second, you can call out to iconv through the shell:

%x{echo ‘ąćęłńóśźż’ | iconv -t ASCII//TRANSLIT}

though in that case you will have to deal with error messages and
whatnot, which can be a bit of a pain.

The third option is write your own wrapper for libiconv. This is what
are probably going to end up doing just to remove the RG2 dependency.

If anyone can come up with any better solutions, believe me I’m all
ears.

Specifically, the script:

$KCODE=‘u’
require ‘iconv’
p Iconv.iconv(‘ASCII//TRANSLIT’, ‘UTF-8’, ‘ąćęłńóśźż’)

when run with options:

ruby -Ku iconv.rb

produces:

["???"]

Whereas in irb:

$ irb
irb(main):001:0> require ‘iconv’
=> false
irb(main):002:0> Iconv.iconv ‘ASCII//TRANSLIT’, ‘UTF-8’, ‘ąćęłńóśźż’
=> [“acelnoszz”]

Any Ruby gurus out there who have any idea why this should be?

Dan[/quote]

Właśnie też napotkałem na ten problem z Iconvem. Wygląda na to, że trzeba użyć setlocale przed wywołaniami Iconva.

require 'dl/import' module Locale extend DL::Importable begin dlload 'libc.so.6' rescue end LC_CTYPE = 0 LC_NUMERIC = 1 LC_TIME = 2 LC_COLLATE = 3 LC_MONETARY = 4 LC_MESSAGES = 5 LC_ALL = 6 begin extern 'char *setlocale(int, const char *)' rescue def self.setlocale(lc, code) end end end
i na początku programu

Locale::setlocale(Locale::LC_CTYPE, '')

(lepiej nie używać LC_ALL)

i wszystko działa jak trzeba.

Tak, i dodatkowo lokale muszą być zainstalowane w systemie dla dango języka docelowego. Natknęłem się na ten problem w zeszłym tygodniu jakoś, trzeba było wygenerować lokale pl_PL.UTF8 dla systemu bo domyślnie były tylo en_US* itd.

$ locale -a

pokaże jakie są zainsatlowane w systemie.