Forum po¶więcone Ruby on Rails i językowi programowania Ruby
Nie jeste¶ zalogowany.
Witam,
Wiem, że problem jest pewnie lamerski, ale brakuje mi trochę obycia z Rubym ;-)
Potrzebuję zamienić wszystkie polskie znaki (±ęłóńżĽć) na ich odpowiedniki w ASCII (aelonzzc). W php mogłem sobie zrobić tak:
Jak podobn± operację wykonać w Rubym (łańcuchy mam zapisane w UTF-8)? Próbowałem kombinować z tr(), ale kod:
slug = "ę± ±ę dupa" slug = slug.tr('±', 'a') slug = slug.tr('ę', 'e')
daje mi jakie¶ dziwne wyniki
(dostaję: aeaa aaae dupa)
Offline
http://wiki.rubyonrails.com/rails/pages … odeStrings lub zaczekaj około dwóch lat na wersję drug± Rubiego.
Offline
Bez przesady, powinno jako¶ dać się to rozwi±zać ;-) PHP ma jeszcze gorsz± obsługę unikodu, a jako¶ sobie można z tym poradzić.
Offline
p_ch napisał:
Jak podobn± operację wykonać w Rubym (łańcuchy mam zapisane w UTF-8)? Próbowałem kombinować z tr()
Z tr() nie masz co kombinować bo to działa na stringach 8 bitowych. W PHP też ci by ta funkcja nie zadziałała. Aby użyć tr() musisz wpierw string przekonwertować do jakiego¶ formatu 8 bitowego. Np.:
require 'iconv' def pl2ascii(s) ascii = "acelnoszzACELNOSZZ" cep = "\271\346\352\263\361\363\234\277\237\245\306\312\243\321\323\214\257\217" s = Iconv.new("cp1250", "UTF-8").iconv(s) s.tr!(cep,ascii) end puts pl2ascii('zażółć gę¶l± jaĽń ZAŻÓŁĆ GʦLˇ JA¬Ń') # => zazolc gesla jazn ZAZOLC GESLA JAZN =begin Do generacji stringa z kodami cep1250 użyłem Pythona: pl = [oct(ord(c)) for c in unicode('±ćęłń󶿼ˇĆĘŁŃӦݬ', 'utf8').encode('cp1250')] print ''.join(["\\%s" % c[1:] for c in pl]) # => \271\346\352\263\361\363\234\277\237\245\306\312\243\321\323\214\257\217 =end
Oczywi¶cie, powyższy kod się wysypie jak masz w tek¶cie jakie¶ niekonwertowalne znaki z utf8 do cp1250.
Ostatnio edytowany przez jzabiello (2006-05-31 15:11:11)
Offline
OK. Dzięki za odpowiedzi.
Mam jeszcze jedn± w±tpliwo¶ć. Przegl±dam sobie kod Typo, żeby zobaczyć jak zrealizowana jest tam zamiana tytułu na permalink. Je¶li tytuł brzmi: "Zażółć gę¶l± jaĽń", to permalink będzie taki: "zażółć-gę¶l±-jaĽń". Typo korzysta z takiego kodu:
class String # Converts a post title to its-title-using-dashes # All special chars are stripped in the process def to_url return if self.nil? result = self.downcase # replace quotes by nothing result.gsub!(/['"]/, '') # strip all non word chars result.gsub!(/\W/, ' ') # replace all white space sections with a dash result.gsub!(/\ +/, '-') # trim dashes result.gsub!(/(-)$/, '') result.gsub!(/^(-)/, '') result end end
Gdy próbuję ten sam kod zastosować u siebie:
slug = link.title.downcase slug.gsub!(/['"]/, '') # strip all non word chars slug.gsub!(/\W/, ' ') # replace all white space sections with a dash slug.gsub!(/\ +/, '-') # trim dashes slug.gsub!(/(-)$/, '') slug.gsub!(/^(-)/, '')
to otrzymuję: "za-g-l-ja". Od czego to zależy?
Offline
To z CodeSnippets: National characters to ascii letters. Moze sie przyda.
Offline
Tu jest inna wersja, bardziej w Ruby-way. Wzbogaca wszystkie stringi o dodatkow± metodę.
require 'iconv' class String def to_ascii ascii = "acelnoszzACELNOSZZ" cep = "\271\346\352\263\361\363\234\277\237" s = Iconv.new("cp1250", "UTF-8").iconv(self) s.tr!(cep,ascii) end end puts 'zażółć gę¶l± jaĽń'.to_ascii # => zazolc gesla jazn
Offline
Ladnie, bo tyle gsubow mnie przerazalo
Dodatkowo mozna latwo rozszerzyc o inne jezyki.
Dla przykladu podam jave. Uzywalem ibm-owskiej bibl icu4j.
import com.ibm.icu.text.Transliterator; public class TextUtils { "NFD; Suplement; [:Nonspacing Mark:] Remove; NFC"; "NFD; Suplement; [\\P{ASCII}\\P{Alpha}] Remove; Lower; NFC"; // "Greek-Latin; Cyrillic-Latin; ru-en;" static TextUtils singleton = null; private TextUtils() { Transliterator.registerInstance( Transliterator.createFromRules("Any-Suplement", suplement, Transliterator.FORWARD)); } public static TextUtils getInstance() { if (singleton == null) { singleton = new TextUtils(); } return singleton; } Transliterator acc = Transliterator.getInstance(customID); return acc.transliterate(text); } return transliterate(accentID, text); } return transliterate(loginID, text); } return s.length() > maxChars ? s.substring(0, maxChars) : s; } }
Jak widac nie do konca sobie transliterator radzil - stad suplement ... ale takie rozw. jest b. wydajne bo nie operuje na regexp.
Offline
Kolejne lamerskie pytanie: jak podpi±ć ten skrypt do mojej aplikacji? ![]()
Zrobiłem tak: utworzyłem plik string_utils.rb w katalogu lib, z kodem podanym przez jzabiello. W environments.rb dodałem linię: require 'lib/string_utils'
No i gdy próbuję wywołać to_ascii to albo się pluje, że nie mógł wczytać iconv, albo że metoda nie istnieje. Webrick chce się uruchomić, gdy w environments.rb jest dodana przeze mnie linia.
Wiem, że to pewnie jedna z najprostszych rzeczy i najgłupszych błędów, ale Ruby jest ci±gle dla mnie czym¶ nowym. Szukałem w dokumentacji, ale nie znalazłem. Będę wdzięczny za pomoc.
Offline
Dodaj samo require 'string_utlis' (bez lib).
Offline
To samo. Może po prostu nie mam biblioteki iconv?
Offline
Pod eclipse (RDT) dziala. Bibl. iconv jest standardowo w ruby. Prawdop. masz inny encoding pliku niz UTF-8.
Ja dostawalem Iconv::IllegalSequence dla cp1250 i iso8859-2.
Tego typu sprawy zniechecaja do Rubiego vs. Java czy Python.
Offline
Pod windowsami standardowo nie ma ani iconv ani gettext. Trzeba to doinstalowac, np. st±d: http://sourceforge.net/project/showfile … _id=25167.
Offline
p_ch napisał:
To samo. Może po prostu nie mam biblioteki iconv?
Uruchom irb i wpisz
require 'iconv'
Jak zwróci true to masz zainstalowane.
Offline
LoadError: No such file to load.
Czyli lipa.
W pełni zadowoliłoby mnie rozwi±zanie używane w typo do tworzenia permalinków (kod, który podałem kilka postów wyżej). Nie mam jednak pojęcia, dlaczego w Typo działa on normalnie, a u mnie usuwa wszystkie polskie znaki.
Offline
Mysle, ze chodzi o wlaczenie multibyte support (tzn. dokladnie utf8) - typo ma to globalnie ustawione w envionment.rb
$KCODE = 'u' require 'jcode'
Opcjonalnie mozesz wlaczyc dla danego wyr. regularnego
expr = /[ˇ±]/u # to 'u' na koncu puts expr.kcode # => utf8
# strip all non word chars result.gsub!(/\W/, ' ')
Powyzszy fragm. z typo pozbawial cie polskich znakow bo nie sa one "word char" w rozumieniu ASCII. /\W/u powinno zalatwic sprawe, ale i tak musisz pozniej podmienic diakrytyki - sprytna metoda zaproponowana przez Jarka Zabiello albo gsub-y z Code Snippets.
PS. Ja mam pod winda standardowo iconv (One-Click Installer, 1.8.4-16 release candidate 1)
Offline
Dzięki, o to mi chodziło :-)
Teraz już ¶miga jak trzeba.
Offline
jzabiello napisał:
Kod: ruby
require 'iconv' def pl2ascii(s) ascii = "acelnoszzACELNOSZZ" cep = "\271\346\352\263\361\363\234\277\237" s = Iconv.new("cp1250", "UTF-8").iconv(s) s.tr!(cep,ascii) end puts pl2ascii('zażółć gę¶l± jaĽń') # => zazolc gesla jazn
jak unowocze¶nić ten kod, żeby przerabiał też duże polskie litery?
Ostatnio edytowany przez bober0 (2008-07-31 12:37:36)
Offline
bober0 napisał:
jzabiello napisał:
Kod: ruby
require 'iconv' def pl2ascii(s) ascii = "acelnoszzACELNOSZZ" cep = "\271\346\352\263\361\363\234\277\237" s = Iconv.new("cp1250", "UTF-8").iconv(s) s.tr!(cep,ascii) end puts pl2ascii('zażółć gę¶l± jaĽń') # => zazolc gesla jaznjak unowocze¶nić ten kod, żeby przerabiał też duże polskie litery?
Trzeba dodać brakuj±ce kody, zobacz poprawion± wersję
Offline
Po przeczytaniu rozwi±zań Obiego i innych wypracowali¶my rozwi±zanie brutalne i brzydkie, ale skuteczne:
class String def to_ascii_brutal #foo = self.downcase.strip foo = String.new(self) #foo = self.clone #.downcase.strip foo.gsub!(/[ˇÀ�?ÂÃ]/,'A') foo.gsub!(/[âäàãáäå�?ă±ǎǟǡǻ�?ȃȧẵặ]/,'a') foo.gsub!(/[Ę]/,'E') foo.gsub!(/[ëêéèẽēĕėẻȅȇẹȩęḙḛ�?ếễểḕḗệ�?]/,'e') foo.gsub!(/[Ì�?ÎĨ]/,'I') foo.gsub!(/[�?iìíîĩīĭïỉ�?ịįȉȋḭɨḯ]/,'i') foo.gsub!(/[ÒÓÔÕÖ]/,'O') foo.gsub!(/[òóôõ�?�?ȯö�?őǒ�?�?ơǫ�?ɵøồốỗổȱȫȭ�?�?ṑṓ�?ớỡởợǭộǿ]/,'o') foo.gsub!(/[ÙÚÛŨÜ]/,'U') foo.gsub!(/[ùúûũūŭüủůűǔȕȗưụṳųṷṵṹṻǖǜǘǖǚừứữửự]/,'u') foo.gsub!(/[ỳýŷỹȳ�?ÿỷẙƴỵ]/,'y') foo.gsub!(/[œ]/,'oe') foo.gsub!(/[ÆǼǢæ]/,'ae') foo.gsub!(/[Ń]/,'N') foo.gsub!(/[ñǹń]/,'n') foo.gsub!(/[ÇĆ]/,'C') foo.gsub!(/[çć]/,'c') foo.gsub!(/[ß]/,'ss') foo.gsub!(/[œ]/,'oe') foo.gsub!(/[ij]/,'ij') foo.gsub!(/[Ł]/,'L') foo.gsub!(/[�?ł]/,'l') foo.gsub!(/[¦]/,'S') foo.gsub!(/[¶]/,'s') foo.gsub!(/[¬Ż]/,'Z') foo.gsub!(/[Ľż]/,'z') #foo.sub!(/[\s\'\"\\\/\?\.\=\+\&\%]$/,'') #foo.gsub!(/[\s\'\"\\\/\?\.\=\+\&\%]/,'_') #foo.gsub!(/_+/,'_') foo end end
Niestety silnik forum brutalnie zamienił nieasciowe znaki na encje htmlowe. W dużym skrócie chodzi o wymienienie wszystkich możliwych literek, jakie maj± zostać wymienione na swoje asciiowe uproszczenia.
Offline
Wrzuc to na pastie.org jesli mozesz napewno sie przyda.
Offline
Może komu¶ się też przydać.
require 'iconv'
require 'unicode'
class String
def to_ascii
return if self.nil?
self.chars.split('').collect { |c| (c[0] <= 127) ? c : translation_hash[c[0]] }.join
end
protected
def translation_hash
@translation_hash ||= setup_translation_hash
end
def setup_translation_hash
accented_chars = "ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛŨÜÝâäàãáäåāă±ǎǟǡǻȁȃȧẵặçëêéèẽēĕėẻȅȇẹȩęḙḛềếễểḕḗệḝiìíîĩīĭïỉǐịįȉȋḭɨḯñòóôõōŏȯöỏőǒȍȏơǫọɵøồốỗổȱȫȭṍṏṑṓờớỡởợǭộǿùúûũūŭüủůűǔȕȗưụṳųṷṵṹṻǖǜǘǖǚừứữửựỳýŷỹȳẏÿỷẙƴỵˇĆĘŁŃӦݬ±ćęłń󶿼".chars.split('')
unaccented_chars = "AAAAAACEEEEIIIIDNOOOOOxOUUUUUYaaaaaaaaaaaaaaaaaaaceeeeeeeeeeeeeeeeeeeeeeeeiiiiiiiiiiiiiiiiinoooooooooooooooooooooooooooooooooooouuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuyyyyyyyyyyyACELNOSZZacelnoszz".split('')
translation_hash = {}
accented_chars.each_with_index { |char, idx| translation_hash[char[0]] = unaccented_chars[idx] }
translation_hash["Æ".chars[0]] = 'AE'
translation_hash["æ".chars[0]] = 'ae'
translation_hash["Œ".chars[0]] = 'OE'
translation_hash["œ".chars[0]] = 'oe'
translation_hash["ß".chars[0]] = 'ss'
translation_hash
end
endOstatnio edytowany przez tczubinski (2008-08-04 23:47:29)
Offline
Offline
tczubinski: ta wersja działa Ci z nowymi railsami?
Offline