Chcę zastąpić znaki ISO-8859-1 z poniższego pliku, aby mieć poprawny dla kodowania 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>

Robiąc kilka badań, które znalazłem, że problem jest związany z językiem locale i udało mi się zbudować ten program awk, ale tylko zastępuje pierwsze 2 znaki (' i *)

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

Jest to prąd wyjściowy (wyświetlanie poniżej częściowej mocy, tylko linie dotknięte przez program):

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

I oczekiwane wyjście to:

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

Próbowałem już podobnego kodu za pomocą sed, ale ten sam problem.

Jak to naprawić?

Poniżej Locale Config:

***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=
3
Ger Cas 22 marzec 2020, 10:25

1 odpowiedź

Najlepsza odpowiedź

Ten problem jest prawdopodobnie spowodowany niedopasowaniem kodowania między plikiem wejściowym a skryptem awk.

Zauważ, że prawdopodobnie istnieje prawdopodobnie (bardzo częste) zamieszanie między ISO-8859-1 a Windows-1252. Próbka HTML w oryginalnym słupku zawiera znaki rozdzielcze, które nie są częścią Układ ISO-8859-1, dzięki czemu z pewnością używa innego kodowania, prawdopodobnie Windows-1252 (który jest superset ISO-8859-1, w tym znaków Dash), ponieważ OP zgłoszono do użycia Ubuntu za pomocą warstwy podsystemu Windows.

Założę się, że plik wejściowy HTML jest rzeczywiście zakodowany w systemie Windows-1252. Więc znaki nie-ASCII (punkty kodowe ≥ 128) Używaj tylko jednego bajtu.

Jeśli program awk jest załadowany z pliku zakodowanego w UTF-8, lub nawet bezpośrednio wpisany w oknie zacisku, który wykorzystuje endoding UTF-8, następnie wyrażenia regularne i dosłowne ciągi osadzone w programie są również zakodowane w UTF-8. Więc znaki nie-ASCII używają wielu bajtów.

Na przykład, znak § (punkt kodu 167 = 0xa7), jest reprezentowany przez bajt A7 w systemie Windows-1252 i sekwencję bajtów C2 A7 w UTF-8. Jeśli używasz gsub(/§/, "S") w zakodowanym programie awk w zakodowanym UTF-8, a następnie wrw wyszukaj sekwencję C2 A7 w pliku wejściowym, który zawiera tylko A7. Nie pasuje. Chyba że jesteś (nie) szczęście, aby mieć postać Â (punkt kodu 194 = 0xC2) spędzony tuż przed §.

Zmiana miejscowości nie pomaga tutaj, ponieważ mówi tylko awk, jak przeanalizować swoje dane wejściowe (dane i program), podczas gdy tego, czego potrzebujesz, jest transkodować dane lub wyrażenia regularne. Aby to pracować, musiałbyś być w stanie określić lokalizację danych niezależnie od ustawień regionalnych programu, który nie jest obsługiwany.

Zastanawiając się więc, że system jest skonfigurowany z UTF-8 Locale, a skrypt awk używa tego ustawienia ustawień (bez względu na to, że jest załadowany z pliku lub wpisany w terminalu), oto kilka metod, których możesz użyć do wyrównania pliku wejściowego oraz wyrażenia regularne na tym samym kodowaniu, tak aby gsub działa zgodnie z oczekiwaniami.

Należy pamiętać, że te sugestie trzymają się pierwszej komendy awk, ponieważ jest źródłem problemu. Ostateczna rura do iconv jest potrzebna tylko wtedy, gdy celowo nie przekształtujesz wszystkich znaków specjalnych, możesz mieć w wejściu do podmiotów HTML. W przeciwnym razie wyjście awk jest zwykłe ASCII, więc już zgodne z UTF-8.

Opcja 1: Konwertuj plik wejściowy z Windows-1252 do UTF-8

Nie ma potrzeby innego iconv krok po każdym w każdym przypadku.

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
   }'

Opcja 2: Konwertuj program awk z UTF-8 do Windows-1252

Ponieważ program awk może też chcieć się bawić. Użyjmy substytucji procesu.

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

Opcja 3: Zapisz skrypt awk / powłoki w pliku zakodowanym w systemie Windows-1252

... z ulubionym narzędziem.

Opcja 4: Przełącz kodowanie sesji terminali do systemu Windows-1252

W przypadku wpisywania / wklejaj komendy awk w terminalu.

Należy pamiętać, że różni się od ustawienia ustawień lokalizacji (LC_CTYPE). Nie jestem świadomy sposobu, aby zrobić to programowo. Jeśli ktoś wie, nie możesz się przyczynić.

Opcja 5: Unikaj znaków innych niż ASCII w programie awk

Ich brzmi dobrą praktyką moim zdaniem.

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
1
luciole75w 26 marzec 2020, 18:47