Как правильно заменить символы ISO-8859-1 на UTF-8? - PullRequest
3 голосов
/ 22 марта 2020

Я хочу заменить символы ISO-8859-1 из файла ниже, чтобы они действовали для кодировки UTF-8.

<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</HEAD>

<BODY>

<A NAME="top"></A>

<TABLE border=0 width=609 cellspacing=0 cellpadding=0>
<TR><td rowspan=2><img src="http://www.example.com" width=10></td>
<TD width=609 valign=top>

<p>'</p>
<p>*</p>
<p>-</p>
<p>—</p>
<p>§</p>
<p>«</p>
<p>»</p>
<p>¿</p>
<p>Á</p>

</TD>
</TR>
</TABLE>

</body>
</html>

Проведя некоторые исследования, я обнаружил, что проблема связана с языком locale и Мне удалось построить эту awk-программу, но она заменяет только первые 2 символа (' и *)

LC_ALL=ISO_8859-1 awk '{
   gsub(/charset=iso-8859-1/, "charset=UTF-8"  ,  $0)
   gsub(/\047/, "\\&apos;"  ,  $0)
   gsub(/*/, "\\&ast;"      ,  $0)
   gsub(/–/, "\\&ndash;"    ,  $0)
   gsub(/—/, "\\&mdash;"    ,  $0)
   gsub(/§/, "\\&sect;"     ,  $0)
   gsub(/«/, "\\&laquo;"    ,  $0)
   gsub(/»/, "\\&raquo;"    ,  $0)
   gsub(/¿/, "\\&iquest;"   ,  $0)
   gsub(/Á/, "\\&Aacute;"   ,  $0)
   print
   }' t.html | iconv -f ISO_8859-1 -t UTF-8

Это текущий вывод (ниже показан частичный вывод, только строки, затронутые программа):

<p>&apos;</p>
<p>&ast;</p>
<p>-</p>
<p>-</p>
<p>§</p>
<p>«</p>
<p>»</p>
<p>¿</p>
<p>Á</p>

и ожидаемый результат:

<p>&ast;</p>
<p>&ndash;</p>
<p>&mdash;</p>
<p>&sect;</p>
<p>&laquo;</p>
<p>&raquo;</p>
<p>&iquest;</p>
<p>&Aacute;</p>

Я уже пробовал подобный код, используя sed, но та же проблема.

Как чтобы это исправить?

Конфигурация ниже локали:

***Ubuntu 18.04.1 LTS

$ locale
LANG=C.UTF-8
LANGUAGE=
LC_CTYPE="C.UTF-8"
LC_NUMERIC="C.UTF-8"
LC_TIME="C.UTF-8"
LC_COLLATE="C.UTF-8"
LC_MONETARY="C.UTF-8"
LC_MESSAGES="C.UTF-8"
LC_PAPER="C.UTF-8"
LC_NAME="C.UTF-8"
LC_ADDRESS="C.UTF-8"
LC_TELEPHONE="C.UTF-8"
LC_MEASUREMENT="C.UTF-8"
LC_IDENTIFICATION="C.UTF-8"
LC_ALL=

1 Ответ

1 голос
/ 26 марта 2020

Эта проблема, вероятно, связана с несоответствием кодировки между входным файлом и сценарием awk.

Пожалуйста, обратите внимание, что, вероятно, существует (очень распространенная) путаница между ISO-8859-1 и Windows -1252 здесь. Образец html в исходном сообщении содержит символы em / en da sh, которые не являются частью макета ISO-8859-1 , поэтому он, безусловно, использует другую кодировку, вероятно, Windows -1252 (который является надмножеством ISO-8859-1, включая символы da sh), поскольку OP сообщил, что использует Ubuntu через уровень подсистемы Windows.

Я тогда Предположим, что входной файл html действительно закодирован как Windows -1252. Поэтому не-ASCII-символы (кодовые точки ≥ 128) используют только один байт.

Если программа awk загружается из файла, закодированного в UTF-8, или даже непосредственно набирается в окне терминала, которое использует UTF- После окончания кодирования, затем регулярные выражения и буквенные строки, встроенные в программу, также кодируются в UTF-8. Поэтому не-ASCII-символы используют несколько байтов.

Например, символ § (кодовая точка 167 = 0xA7) представлен байтом A7 в Windows -1252 и последовательностью байтов. C2 A7 в UTF-8. Если вы используете gsub(/§/, "S") в своей программе awk в кодировке UTF-8, то awk ищет последовательность C2 A7 во входном файле, который содержит только A7. Это не будет соответствовать. Если вы (не) достаточно удачливы, чтобы персонаж Â (кодовая точка 194 = 0xC2) зависал перед вашим §.

Смена локали здесь не помогает, потому что она только сообщает awk, как для анализа входных данных (данных и программы), тогда как здесь вам нужно перекодировать либо данные, либо регулярные выражения. Чтобы это работало, вы должны иметь возможность указывать языковой стандарт данных независимо от языкового стандарта программы, который не поддерживается.

Итак, при условии, что ваша система настроена с UTF-8 locale и что ваш awk-скрипт использует эту локаль (независимо от того, загружен ли он из файла или введен в терминале), вот несколько методов, которые можно использовать для выравнивания входного файла и регулярных выражений в одной и той же кодировке, чтобы gsub работал как и ожидалось.

Обратите внимание, что эти предложения относятся к вашей первой команде awk, поскольку она является источником проблемы. Последний канал для iconv необходим только в том случае, если вы намеренно не преобразуете все специальные символы, которые могут иметь во входных данных, в html сущности. В противном случае вывод awk является простым ASCII, поэтому уже совместим с UTF-8.

Опция 1: преобразовать входной файл из Windows -1252 в UTF-8

Нет необходимости в другом iconv шаг в этом случае в любом случае.

iconv -f WINDOWS-1252 t.html | awk '{
   gsub(/charset=iso-8859-1/, "charset=UTF-8")
   gsub(/\047/, "\\&apos;")
   gsub(/\*/, "\\&ast;")
   gsub(/–/, "\\&ndash;")
   gsub(/—/, "\\&mdash;")
   gsub(/§/, "\\&sect;")
   gsub(/«/, "\\&laquo;")
   gsub(/»/, "\\&raquo;")
   gsub(/¿/, "\\&iquest;")
   gsub(/Á/, "\\&Aacute;")
   print
   }'

Вариант 2: преобразовать программу awk из UTF-8 в Windows -1252

Поскольку программе awk тоже может быть интересно , Давайте используем замену процесса.

awk -f <(iconv -t WINDOWS-1252 <<'EOS'
{
   gsub(/charset=iso-8859-1/, "charset=UTF-8")
   gsub(/'/, "\\&apos;")
   gsub(/\*/, "\\&ast;")
   gsub(/–/, "\\&ndash;")
   gsub(/—/, "\\&mdash;")
   gsub(/§/, "\\&sect;")
   gsub(/«/, "\\&laquo;")
   gsub(/»/, "\\&raquo;")
   gsub(/¿/, "\\&iquest;")
   gsub(/Á/, "\\&Aacute;")
   print
}
EOS
) t.html

Вариант 3: сохранить скрипт awk / schell в файле, закодированном в Windows -1252

... с вашим любимым инструментом.

Вариант 4: переключите кодировку сеанса терминала на Windows -1252

В случае, если вы, конечно, набираете / вставляете команду awk в терминале.

Обратите внимание, что это отличается от установки локали (LC_CTYPE). Я не знаю способ сделать это программно. Если кто-то знает, не стесняйтесь вносить свой вклад.

Вариант 5: в программе awk вообще избегайте использования символов, отличных от ASCII

В любом случае, на мой взгляд, это хорошая практика.

awk '{
   gsub(/charset=iso-8859-1/, "charset=UTF-8")
   gsub(/\047/, "\\&apos;")
   gsub(/\*/, "\\&ast;")
   gsub(/\226/, "\\&ndash;")
   gsub(/\227/, "\\&mdash;")
   gsub(/\247/, "\\&sect;")
   gsub(/\253/, "\\&laquo;")
   gsub(/\273/, "\\&raquo;")
   gsub(/\277/, "\\&iquest;")
   gsub(/\301/, "\\&Aacute;")
   print
   }' t.html
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...