UTF-8の半角スペースには2種類ある

2014-06-26

旧ブログ

t f B! P L

(2018.3.24追記。根本的に理解が間違っていたのでほとんど書き直しました。)

SyntaxHighlighter3.0.9より前のバージョンで表示させているコードをChromeからPyCharmへコピペすると行頭のスペースが認識されません。FirefoxやIEからでは問題は起きません。Chromeからコピペするとノンブレーキングスペースが正しくペーストされずutf-8エンコードのままペーストされてしまうのが原因でした。SyntaxHighlighter3.0.9ではそうならないように対策されています(linuxBean14.04(111)SyntaxHighlighter3.0.9をビルドする:成功編参照。)。

Unicodeのノンブレーキングスペースとブレーキングスペース


ノンブレーキングスペースとは改行されないスペースともいわれます。

HTMLでは通常の半角スペースは2個以上あるとブラウザに1個にまとめられてしまいますので、連続したスペースをブラウザに表示させるにはノンブレーキングスペースにする必要があります。

ノンブレーキングスペースのUnicodeのコードポイントは、U+00A0です。

U+00A0をutf-8エンコーディングすると16進数ではC2A0になります(Python: Unicodeのコードポイントとバイト列との変換)。

C2A0はバイト列の16進数なので文字列としてペーストしても文字として認識されません。

 はというのはノンブレーキングスペースのHTMLの文字参照です。

ブラウザに出力するHTMLではUnicodeのコードポイントのU+00A0の代わりに が使えますが、エディタでは はノンブレーキングスペースとしては認識されずただの「 」という文字列として認識されます。

通常の半角スペース(ブレーキングスペース)のコードポイントはU+0020で、このutf-8エンコーディングは20になります。

PyCharmが認識できない文字

def gcd(x, y):
    if y == 0:
        return x
    else:
        return gcd(y, x % y)
print(gcd(24, 9))
このSyntaxHighlighterで表示させているコードをダブルクリックするとコードだけが選択できます。


これをChromeからPyCharm3.4にペーストします。


行頭にスペースはちゃんと4個になっていますが赤色になってエラーになっています(このブログではSyntaxHighlighterを対策済みのものにバージョンアップしたのでこの通りエラーにはなりません)。

このようになるのはWindowsではChromeとSleipnir4からコピペしたときだけです。

(LinuxではChromeとOperaでなりました。)

FirefoxやIEからでは問題は起こりません。

このエラーがでたままでは実行できません。


赤色のところにカーソルをもってくるとエラーの内容が表示されます。

Statement expected, found BAD_CHARACTER

これは行頭の半角スペースが認識できない文字になっているのが原因です。

ためしに同じ内容をWindows7のメモ帳にペーストします。


見た目は問題ありません。

このファイルを保存してみます。


全角文字が含まれていないので文字コードは「ANSI」(ASCII)でいけると思ったらエラーがでてきます。


ASCII文字しかないはずなのにASCIIでは保存できない「Unicode形式」の文字を含んでいるといわれます。

そのまま「OK」をクリックしてファイルを保存したあとそのファイルをメモ帳で開き直してみます。


行頭の半角スペースがすべて「?」に置換されてしまっていますね。

PyCharmで赤色に表示された部分と一致しています。

この部分が認識できない文字コードのものです。

最初に書いたようにUnicodeにはU+00A0(ノンブレーキングスペース)とU+0020(ブレーキングスペース)の2種類があり、ChromeからコピペするとU+00A0が正しくペーストされずにutf-8エンコードでバイト列になったC2A0が文字列としてペーストされてしまうからです。

PyCharmで間違った文字コードC2A0を半角スペースに置換する


PyCharmでこの赤色で表示されているスペースの一文字分を選択します。


この状態でメニューからEdit→Find→Replace。

すると置換ツールが表示されます。


ここで上の欄には置換対象の文字列、下の欄には置換後の文字列を入力します。

UTF-8の半角スペースを選択した状態でメニューからEdit→Find→Replace、で自動的に置換対象の欄にC2A0が入力されているので、上の欄はいじってはいけません。

下の置換後の文字列をクリックした後、半角スペースを入力します。


半角スペースを入力しても表示されませんので不安になりますが、よくみると入力欄の右端にxボタンが表示されます。

入力欄が本当に空っぽですとこのxボタンは表示されません。

試しに上の欄にクリックしてみると右端にxボタンが出現されるはずです。

「Replace all」ボタンをクリックします。

これで赤い背景色は一掃されるはずです。

PyCharmで一発置換するマクロを作ろうとしましたがうまくつくれませんでした。

LibreOffice Writerでは灰色に表示される



LibreOffice 4.2.2.1のWriterにペーストするとこのように灰色に表示されます。

印刷プレビューではこの灰色は表示されないので実用上は問題なさそうですけど、理由を知らないと気持ち悪いですよね。

Geanyで一発置換する

(2015.6.7追記。以下はlinuxBeanの場合です。linuxBean14.04(26)Geanyのビルドコマンドの設定参照。)


 置換 sed -i -e 's/\xC2\xA0/ /g' %f

Geanyの「ビルドコマンドを設定」の「コマンドの実行」でこの「 置換」を設定すると開いているファイルの不正なノーブレークスペースだったコードが半角スペースに置換されます。


Geanyでは見た目では不正なコードが混じっているかがわかりません。

ビルド→ 置換、を実行します。


「再読み込みしますか?」、といわれるので「再読み込み」します。


これで半角スペースに置換されてPythonスクリプトと認識されて折り畳みなどできるようになりました。

参考にしたサイト


ノーブレークスペース - Wikipedia
半角スペースと違ってブラウザで1個に省略されません。

文字参照 - Wikipedia
HTMLで直接記述できない文字や記号表記する方法

Geany : Home Page
ソースコードエディタ。

sed コマンド | コマンドの使い方(Linux) | hydroculのメモ
文字列置換などを行うコマンド。

linux - use sed to replace nbsp, 160, Hex 00a0, Octal 240, non-breaking space - Super User
sedでノーブレークスペースを普通の半角スペースに置換する例が載っています。

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ