奇妙な文字を含むUTF-8ファイルがあります。
<96>
これはvi
での表示方法です
gedit
での表示方法
libreOfficeでどのように表示されるか
そのため、次のような一連の基本的なUnixツールの動作がおかしくなります。
cat file
キャラクターを消滅させ、more
も同様にgrep
は、文字が存在しないかのように、何も表示しません。プログラムfile
は正常に動作し、UTF-8ファイルとして認識します。また、ファイルの性質上、ウェブからのコピーアンドペーストによるものである可能性が高く、キャラクターは最初はEMDASHを表していました。
私の基本的な質問は:
ファイルはここにあります: file.txt
このファイルには、バイトC2 96
が含まれています。これは、コードポイントU + 0096の TF-8 エンコーディングです。そのコードポイントは C1制御文字 の1つであり、一般にSPAの「ガードされた領域の開始」(または「保護された領域」)と呼ばれます。これは現代のシステムにとって有用な文字ではありませんが、そこにあることは有害である可能性は低いです。
これの元のソースは、途中で誤ってトランスコードされた一部のシングルバイト8ビットエンコーディングのバイト0x96である可能性があります。おそらくこれは元々 Windows CP1252 enダッシュ "–"であり、そのエンコーディングにバイト値96が含まれています。他のほとんどのもっともらしい候補は、80-9Fの位置にコントロールセットがあり、UTFに変換されています- 8ラテン-1( ISO/IEC 8859-1 )であるかのように、これは珍しいことではありません。これにより、バイトが制御文字として解釈され、見たとおりに変換されます。
このファイルは、glibcの一部であるiconv
ツールで修正できます。
iconv -f utf-8 -t iso-8859-1 < mwe.txt | iconv -f cp1252 -t utf-8
私のためにあなたの最小限の例の正しいバージョンを生成します。これは、最初にUTF-8をラテン1に変換し(以前の誤訳を反転)、次にthatをcp1252として再解釈して、UTFに戻します。 -8正しく。
ただし、実際のファイルの他の内容によって異なります。 Latin-1以外の文字がある場合、最初のステップでそれらを正しくエンコードできないため、失敗します。
Iconvがない場合、または実際のファイルで機能しない場合は、sedを使用してバイトを直接置き換えることができます。
LC_ALL=C sed -e $'s/\xc2\x96/\xe2\x80\x93/g' < mwe.txt
これは、C2 96
をUTF-8 en dashエンコーディングE2 80 93
に置き換えます。あなたはそれを例えばに置き換えることもできます\xe2\x80\x93
を--
に変更して、ハイフンを1つまたは2つ。
同様の方法でgrepできます。実際のバイトを読み取るためにLC_ALL=C
を使用しており、grep
が物事を解釈しないようにしています。
LC_ALL=C grep -R $'\xc2\x96` .
これらのバイトが表示されるこのディレクトリの下のあらゆる場所にリストされます。バイナリファイルにはバイトのペアがかなり頻繁に含まれるため、コンテンツが混在している場合は、テキストファイルのみに制限することをお勧めします。
0x96はWindowsコードページ1252のenダッシュです。その前のc2
バイトは、全角文字のデフォルトの最初のバイトのようです。他の誰かがそれについてより正確に説明することができます。
他の出現箇所を検索するには、コマンドモードでカーソルをその上に置き、yl
(1文字をヤンク)を押してから、/<Ctrl>+r"
と入力します。 (ctrl + rを使用すると、レジスタの内容をコマンドに挿入できます。"
レジスタは、最後にヤンクされたものです)。
端末でレンダリングする場合は、2つのハイフンに置き換えてください。それがあなたが持っているbibtexファイルであるならば、2つのハイフンはそれをキーインする適切な方法です。
キャラクターの出現をどのように見つけることができるかを示すために、xxd
のようなhexdumpツールを介してパイプすることができます。
$ cat tmp | xxd | grep c296
00000000: 7061 6765 733d 7b31 c296 3935 7d2c 0a70 pages={1..95},.p
00000020: 6765 733d 7b31 c296 3935 7d2c 0a70 6167 ges={1..95},.pag
00000040: 733d 7b31 c296 3935 7d2c 0a70 6167 6573 s={1..95},.pages
00000060: 7b31 c296 3935 7d2c 0a70 6167 6573 3d7b {1..95},.pages={
00000080: c296 3935 7d2c 0a70 6167 6573 3d7b 31c2 ..95},.pages={1.
00000090: 9639 357d 2c0a 7061 6765 733d 7b31 c296 .95},.pages={1..
000000b0: 357d 2c0a 7061 6765 733d 7b31 c296 3935 5},.pages={1..95
000000d0: 2c0a 7061 6765 733d 7b31 c296 3935 7d2c ,.pages={1..95},
000000f0: 7061 6765 733d 7b31 c296 3935 7d2c 0a70 pages={1..95},.p
00000110: 6765 733d 7b31 c296 3935 7d2c 0a70 6167 ges={1..95},.pag
00000130: 733d 7b31 c296 3935 7d2c 0a70 6167 6573 s={1..95},.pages
00000150: 7b31 c296 3935 7d2c 0a70 6167 6573 3d7b {1..95},.pages={
ファイル内のテキストはpages = {1113},
です。はい、数字1113
のように見えますが、実際には最初の1
の後に別の文字があります。そして、はい、このWebページの編集リンクから文字列をコピーアンドペーストして、エンコードされた文字を取得できます。
いくつかのツールで文字列の内部を見ることができます:
$ a='pages = {1113},'
または、明示的に明確にして、編集ページを使用せずに簡単にコピーして貼り付けることができるようにします。
$ a=$(printf 'pages = {1\xc2\x96113},')
$ echo "$a" | od -An -tx1c
70 61 67 65 73 20 3d 20 7b 31 c2 96 31 31 33 7d
p a g e s = { 1 302 226 1 1 3 }
2c 0a
, \n
$ echo "$a" | sed -n l
pages = {1\302\226113},$
$ echo "$a" | xxd
00000000: 7061 6765 7320 3d20 7b31 c296 3131 337d pages = {1..113}
00000010: 2c0a
したがって、文字は2バイトの値c2 96
(16進数)または302 226
(8進数)です。
これは、おそらく96
のバイト値のUTF-8エンコーディングであるか、Unicode文字U-0096
として表現されています。
その値は、現在のところUTF-8、より良いのはISO-8859-1で、C1領域の制御文字( Wikipedia page )および( nicode PDF )128から159までの10進数です。具体的には、U-0096は「START OF GUARDED AREA」または[〜#〜] spa [〜#〜]と呼ばれます。
その値(12月150日)はASCII範囲(0-127)を超えており、(以前は)使用されたコードページに応じていくつかの文字を表すために使用されていました。これは、以前はダッシュ(範囲1-113をマークする)で、Windows-1252( Microsoftページ )( Wikipedia 1252 )でエンコードされ、enダッシュ(2つのダッシュenとem)( Wikipedia en dash )または、簡単に言えば、ダッシュ(-
)。
実際には、制御文字は有効な文字であり、めったに使用されませんが、それでも有効です。
ただし、編集を簡単にするために、ダッシュに置き換えることができます。
<file.txt sed 's/\xc2\x96/-/'
sed -n '/\xc2\x96/p' # will print lines that contain that character.
または、grepは文字を検索し(文字は印刷できないため、色のハイライトは表示されません)、行を印刷します。
c="$(printf "\U96")" ; grep "$c" file.txt
より広義には、その制御文字範囲内のすべての文字を見つけ、そのような文字を含むファイルをリストします。
grep -rlP "[\x80-\x9f]"
これは、文字に一致するファイルを一覧表示します(-l
)。
grep -rlP "\x96"