Ако последователностите от байтове са действително невалидни за кодирането (UTF-8), тогава в ruby 2.1+ можете да използвате метода String#scrub. По подразбиране той ще замени невалидните знаци с „знака за заместване на unicode“ (обикновено представен като въпросителен знак в поле), но можете също да го използвате, за да ги премахнете изцяло.
Въпреки това, както отбелязвате, вашият „странен байт“ всъщност е валиден UTF-8, представляващ кодовата точка на Unicode „“, контролния знак SHIFT IN
. (Добра работа при намирането на действителните включени байтове/символи, това е трудната част!)
Така че трябва да сме наясно какво имаме предвид под „такива герои“, ако искаме да ги премахнем. Герои като какво?
Nokogiri се оплаква, че е невалиден в XML област "PCDATA" (анализирани данни за знаци). Защо би бил легален unicode/UTF-8, но невалиден в XML PCDATA? Какво е законно в XML символните данни? Опитах се да го разбера, но става объркващо с спец. очевидно казва, че някои герои са „обезсърчени“ (какво?), и прави това, което според мен са противоречиви твърдения за други неща.
Не съм сигурен точно какви символи Nokogiri ще забрани от PCData, ще трябва да погледнем източника на Nokogiri (или по-вероятно източника на libxml) или да се опитаме да зададем въпрос на някой, който знае повече за източника на nokogiri/libxml.
„“ обаче е „контролен знак“, малко вероятно е да искате контролни знаци във вашите XML данни за символи (освен ако не знаете, че го правите), а спецификацията на XML изглежда обезсърчава контролните знаци (и очевидно Nokogiri/libxml всъщност ги забранява ?). Така че един от начините за тълкуване на "знаци като този" е "контролни знаци".
Можете да премахнете всички контролни знаци от низ с този регулярен израз, например:
"Some string \u000F more".gsub(/[\u0001-\u001A]/ , '') # remove control chars, unicode codepoints from 0001 to 001A
# => "Some string more"
Ако интерпретираме „символи като този“ като всеки знак, който не се отпечатва -- по-широка категория от „контролни знаци“ и ще включва някои, с които nokogiri изобщо няма проблем. Можем да опитаме да премахнем малко повече от просто контролни знаци, като използваме поддръжката на ruby за класове символи на unicode в регулярните изрази:
some_string.gsub(/[^[:print:]]/ , '')
[:print]
е документиран доста неясно като "изключва контролни знаци и подобни", така че това донякъде съвпада с нашата неясна спецификация на това, което искаме да правим. :)
Така че наистина зависи какво имаме предвид под "герои като този". Наистина, „знаци като този“ за вашия случай вероятно означава „всеки символ, който Nokogiri/libxml ще откаже да разреши“, и се страхувам, че всъщност не съм отговорил на този въпрос, защото съм не съм сигурен и не можах лесно да го разбера. Но в много случаи премахването на контролни символи или още по-добре премахването на символи, които не съвпадат с [:print]
, вероятно ще се справи добре, освен ако нямате причина да искате контролни символи и подобни да останат (ако сте знаели, че имате нужда от тях като разделители на записи, например).
Ако вместо да премахнете, сте искали да ги замените с unicode replacement char, който обикновено се използва за заместване на „байтова последователност, с която не можахме да се справим“:
"Shift in: \u000F".gsub(/[^[:print:]]/, "\uFFFD")
# => "Shift in: �"
Ако вместо да ги премахнете, искате да ги избегнете по някакъв начин, те могат да бъдат реконструирани след анализ на XML.... попитайте отново с това и аз ще го разбера, но все още не съм го направил. :)
Добре дошли в справянето с проблеми с кодирането на знаци, понякога наистина става объркващо.
person
jrochkind
schedule
23.02.2015