Piszę robota w języku Ruby (1.9), który zużywa dużo kodu HTML z wielu przypadkowych witryn.
Próbując wyodrębnić linki, zdecydowałem się po prostu użyć .scan(/href="(.*?)"/i)
zamiast nokogiri / hpricot (duże przyspieszenie). Problem w tym, że teraz otrzymuję dużo " invalid byte sequence in UTF-8
" błędów.
Z tego, co zrozumiałem, net/http
biblioteka nie ma żadnych konkretnych opcji kodowania, a rzeczy, które wchodzą, są w zasadzie nieprawidłowo oznaczone.
Jaki byłby najlepszy sposób pracy z przychodzącymi danymi? Próbowałem .encode
z ustawionymi zamiennikami i nieprawidłowymi opcjami, ale jak dotąd bez powodzenia ...
109
'U*'
cofa'C*'
?Odpowiedzi:
W Ruby 1.9.3 możliwe jest użycie String.encode do "zignorowania" nieprawidłowych sekwencji UTF-8. Oto fragment, który będzie działał zarówno w wersji 1.8 ( iconv ), jak i 1.9 ( kodowanie String # ):
lub jeśli masz naprawdę kłopotliwe dane wejściowe, możesz wykonać podwójną konwersję z UTF-8 na UTF-16 iz powrotem na UTF-8:
źródło
file_contents.encode!('UTF-16', 'UTF-8', :invalid => :replace, :replace => '')
file_contents.encode!('UTF-8', 'UTF-16')
force_encoding
. Jeśli odczytałeś ISO8859-1 jako UTF-8 (a więc ten ciąg zawiera nieprawidłowy UTF-8), możesz go "reinterpretować" jako ISO8859-1 z the_string.force_encoding ("ISO8859-1") i po prostu działać z tym ciągiem w jego prawdziwym kodowaniu..encode('UTF-8')
działa i nie są wykonywane żadne testy. Dokumentacja Ruby Core do kodowania . Jednak przekonwertowanie go na UTF-16 wymusza najpierw przeprowadzenie wszystkich kontroli nieprawidłowych sekwencji bajtów, a zastępowanie jest wykonywane w razie potrzeby.Zaakceptowana odpowiedź ani inna odpowiedź mi nie pasuje. Znalazłem ten post, który zasugerował
To rozwiązało problem.
źródło
Moje obecne rozwiązanie polega na uruchomieniu:
Pozwoli to przynajmniej pozbyć się wyjątków, które były moim głównym problemem
źródło
valid_encoding?
którą wydaje się wykrywać, kiedy coś jest nie tak.val.unpack('C*').pack('U*') if !val.valid_encoding?
.\xB0
plecy do symboli stopni. Nawetvalid_encoding?
wraca prawda, ale ja jeszcze sprawdzić, czy nie ma i rozebrać się znaki się naruszeń za pomocą odpowiedź Amir jest powyżej:string.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
. Próbowałem teżforce_encoding
trasy, ale to się nie udało.Spróbuj tego:
źródło
Zalecam użycie parsera HTML. Po prostu znajdź najszybszy.
Przetwarzanie kodu HTML nie jest tak łatwe, jak mogłoby się wydawać.
Przeglądarki analizują nieprawidłowe sekwencje UTF-8 w dokumentach HTML UTF-8, po prostu umieszczając symbol „ ”. Zatem po przeanalizowaniu nieprawidłowej sekwencji UTF-8 w kodzie HTML otrzymany tekst jest prawidłowym ciągiem.
Nawet wewnątrz wartości atrybutów musisz dekodować jednostki HTML, takie jak amp
Oto świetne pytanie, które podsumowuje, dlaczego nie można wiarygodnie przeanalizować HTML za pomocą wyrażenia regularnego: RegEx pasuje do otwartych tagów z wyjątkiem tagów niezależnych XHTML
źródło
To wydaje się działać:
źródło
źródło
Napotkałem ciąg znaków, który zawierał mieszankę angielskiego, rosyjskiego i kilku innych alfabetów, co spowodowało wyjątek. Potrzebuję tylko języka rosyjskiego i angielskiego, a to obecnie działa dla mnie:
źródło
Podczas gdy rozwiązanie Nakilona działa, przynajmniej jeśli chodzi o omijanie błędu, w moim przypadku miałem ten dziwny, przerobiony znak pochodzący z Microsoft Excela przekonwertowany na CSV, który rejestrował się w ruby jako (pobierz to) cyrylicę K, która w ruby był pogrubionym K. Aby to naprawić, użyłem „iso-8859-1”, a mianowicie.
CSV.parse(f, :encoding => "iso-8859-1")
, co zmieniło moje dziwaczne, deaky cyrillic K w znacznie łatwiejsze w zarządzaniu/\xCA/
, które mogłem następnie usunąć za pomocąstring.gsub!(/\xCA/, '')
źródło
Przed użyciem
scan
upewnij się, żeContent-Type
nagłówek żądanej strony totext/html
, ponieważ mogą istnieć linki do rzeczy, takich jak obrazy, które nie są zakodowane w UTF-8. Strona może być równieżhref
w formacie innym niż HTML, jeśli wybrałeś element w rodzaju<link>
elementu. Sposób sprawdzenia tego zależy od używanej biblioteki HTTP. Następnie upewnij się, że wynikiem jest tylko ascii zString#ascii_only?
(nie UTF-8, ponieważ HTML powinien używać tylko ascii, encje mogą być używane w inny sposób). Jeśli oba te testy przejdą pomyślnie, można go bezpiecznie używaćscan
.źródło
Jeśli nie „przejmujesz się” danymi, możesz po prostu zrobić coś takiego:
search_params = params[:search].valid_encoding? ? params[:search].gsub(/\W+/, '') : "nothing"
Po prostu mi to
valid_encoding?
zdawało. Moje jest polem wyszukiwania, więc w kółko znajdowałem tę samą dziwność, więc użyłem czegoś w stylu: po prostu nie psuj systemu. Ponieważ nie kontroluję doświadczenia użytkownika, aby przeprowadzić automatyczną weryfikację przed wysłaniem tych informacji (np. Automatyczna informacja zwrotna z napisem „dummy up!”), Mogę po prostu wziąć to, usunąć i zwrócić puste wyniki.źródło