「&nbsp」は見えない文字で半角スペースに似てます

「HTML表示」の編集画面を良く開く人は見慣れていると思いますが、編集画面で「Enter」を打つと「<p>&nbsp</p>」というコードが生成されます。

 

 

「p要素」は段落を意味するので「<p>見えない文字</p>」で短い1行を作り、これは改行(空白行を入れる)ことになります。 これを DevToolsで見ると、下の様に「<p><br></p>」と解釈される様です。

 

 

良く判らないが、これがアメブロ編集画面の標準の「改行」の姿です。 ここに出てくる「&nbsp」について調べると、実は1個の文字らしい。 ユニコードのエスケープ表記を使うと「\u00A0」だそうで、普通の半角空白は「\u0020」で、これとは異なるものです。 なぜ半角空白を持ちだしたかというと、「\u00A0」も半角空白と同じ幅で空白として文字列上に幅を持つからです。

 

このあたりの特殊文字の違いは複雑で、興味がある方は調べて見てください。

 

 

pre枠でコード表記をした場合の空白

下のコードを表記したpre枠を例にします。

 

 

これを DevToolsで見ると、グレー背景の「&nbsp;」が沢山混ざり、多くの場合は「半角空白」と交互に並んでいます。

 

 

これは編集画面の「HTML表示」でも下の様に全く同じです。

 

 

なぜ「&nbsp」が混ざり込むのかは判りません。 文字数が大変増えそうに見えますが、「&nbsp」は1文字の「半角空白」と同じで、本来はその心配はないはずです。 HTML編集枠やDevToolsが「特殊な空白」と表示しているだけですから。

 

しかし、アメブロの「最新版エディタ」では、「HTML表示」の編集画面の文字数カウントで文字数制限を判定している様です。

 

 

文字数表示(これは通常表示の文字数らしい)が同じでも、「&nbsp」の含まれたコードは上図の様に文字数制限を超え、「半角空白」に置き換えた場合は制限を越えない場合が出て来ます。 つまり行数の多いコードでは文字数制限に関係してきます。

 

また、このページのツールは改行の「&nbsp;」は対象外ですが、改行(空白行)は、文字数制限のカウントでは「<p>&nbsp;</p>」は「13文字」となり、「<br>」の「4文字」に比べて、ずいぶん無駄です。 長い記事で文字数制限を超えた場合に、改行を「<br>」(Shift + Enter)で書き換えると、クリアできる場合が有り得ます。 

 

この文字数問題以上に「半角空白」の方がHTML表示が見易いのは事実です。 そこで「&nbsp」を「半角空白」に置き換えるツールを作りました。 このツールは、記事内の全て置き換えるのではなく、「pre枠」内のみで置換え処理をします。

 

 

先ず結果から

上の例のコードを実際に書換えて DevToolsで見たところです。

 

 

通常表示や実際のブログ画面は同じですが、HTML表示とDevTools表示は大変にすっきりしました。

 

JavaScriptのコードをブログ掲載する場合は、「通常表示」編集枠の「pre枠」内にコードをペーストするのが無難です。 JavaScriptのコードは、タグ括弧「<」「>」がコード中に含まれる事があり、「HTML表示」の編集枠でこれをペーストすると想定外の事になります。 しかし、その代償として「&nbsp」が大量に混入するのです。

 

ちなみに、「HTML表示」の編集枠ではコメント行の「<」「>」も実効してしまう事があり、大失敗を経験しました。 コード内のタグ括弧は、コメント部も全部実効すると考えるべきです。

 

ツールの使い方

❶「To Space (nbsp)」のコードを「Tampermonkey」に登録します。

 

❷ 変換処理をするスクリプトコードだけを、新規の「通常表示」の編集枠を開いて貼付けます。 この新規編集枠は、処理場所として利用するだけです。

 

❸ ショートカットキー「Ctrl + F10」を押すと、変換を実行するかどうかの選択ダイアログが表示され、これに「OK」を押すと一瞬で変換が行われます。

 

❹ 変換と同時に、コード全体が「pre枠」に入って表示されます。 これは「pre枠」に入れないと、変換された「半角空白」が自動削除されるからです。

 

❺ 変換されたコードをブログページに掲載するには、「HTML編集枠」どうしのコピー&ペーストが必要です。「通常編集枠」どうしでコピー&ペーストでは「&nbsp」が再び生成されてしまいます。

 

コード

〔 To Space (nbsp) 〕 ver. 0.1

// ==UserScript==
// @name         To Space (nbsp)
// @namespace  http://tampermonkey.net/
// @version       0.1
// @description  HTML編集で「&nbsp」を半角空白に変更する
// @author        Ameba blog User
// @match        https://blog.ameba.jp/ucs/entry/srventry*
// @grant         none
// ==/UserScript==

window.addEventListener('load', function(){
    'use strict';

let editor_iframe;
let iframe_doc;
let iframe_body;
let nbsp;

var target=document.getElementById('cke_1_contents'); // 監視 target
var monitor=new MutationObserver(catch_key);
monitor.observe(target, {childList: true}); // ショートカット待受け開始

catch_key();


function catch_key(){
    editor_iframe=document.querySelector('.cke_wysiwyg_frame');
    if(editor_iframe !=null){ // WYSIWYG表示が実行条件

        iframe_doc=editor_iframe.contentWindow.document;
        iframe_doc.addEventListener("keydown", check_key);

        document.addEventListener("keydown", check_key);

        function check_key(event){
            if(event.which==17 || event.ctrlKey==true){
            if(event.which==121 || event.keyCode==121){ // ショートカット「Ctrl+F10」
                event.stopImmediatePropagation();
                start_select(); }}}}} // catch_key


function start_select(){

    editor_iframe=document.querySelector('.cke_wysiwyg_frame');
    iframe_doc=editor_iframe.contentWindow.document;
    iframe_body=iframe_doc.querySelector('body.cke_editable');

    let regex = new RegExp('\u00A0', 'g');
    nbsp=iframe_body.innerText.match(regex);

    let ok=confirm(" ⏬「&nbsp」" + nbsp.length + " 個を半角空白に変換します");
    if(ok){ to_space(); }}


function to_space(){
    let style_text=['background: #fafafa; border: 1px solid #aaa; overflow-y: hidden;',
                          'padding: 0 30px; max-width: 660px'].join(' ');
    let insert_node_d;

    insert_node_d=iframe_doc.createElement('div');
    insert_node_d.setAttribute('style', style_text);
    insert_node_d.appendChild(iframe_doc.createElement('pre'));
    insert_node_d.lastChild.setAttribute('style', 'white-space:pre');
    insert_node_d.lastChild.appendChild(iframe_doc.createElement('br'));

    insert_node_d.lastChild.innerText=iframe_body.innerText.replace(/\u00A0/g , '\u0020');
    iframe_body.innerHTML='';
    iframe_body.appendChild(insert_node_d);
 }

});

 

 

改善の余地あり

書換え場所に新規の編集画面を用意する必要があり、そこからのコピペ作業も手間です。 試作コードなので、ページ上の対象コード以外の文字列にも影響します。 特定の「pre枠」だけを指定して処理ができれば、変換の結果をそのまま保存できます。 操作上で発展させたいところです。