Markdown の改行を無視してほしい

Hexo (というか Markdown 一般)で文章を書いているとき、段落の途中で改行を入れることが普通にあります。物理的な1行が長すぎるとテキストエディタで扱いにくいし、 git の diff も見づらくなってしまいます。

Hexo の Markdown 処理系は、ひとかたまりのテキスト(空行を区切りとする一段落)をひとつのパラグラフ(HTML の p 要素)に変換してくれます。このとき、元のソースファイルの改行をそのまま保存して HTML に出力します。

例)

今日はいい天気ですね。明日も晴れるでしょうか?

<p>今日はいい天気ですね。明日も晴れるでしょうか?</p>

さて、これはこれで一見すると問題無さそうですが、現状の Web ブラウザでは、通常、改行が半角スペースとして解釈されてしまいます。

今日はいい天気ですね。 明日も晴れるでしょうか?

厳密に言うと、CSS の white-space プロパティの値とその解釈に依存していて、通常の設定 (white-space: normal) ではブラウザがコンテキストに従って「よきに計らって」くれることになっているのですが(半角スペース1個と解釈せずに削除してしまってもよい)、まぁ、そこは CJK 文字圏のマイナーさということで、 Firefox とか Google Chrome とかは無条件で改行文字を半角スペースに変換します。
https://www.w3.org/TR/CSS2/text.html#white-space-prop

ちなみに CSS3 (CSS Text Module Level 3) のドラフトでは、中国語・日本語・Yi 文字に挟まれた改行(や半角スペースなど)は無視するように明記されています(期待!)
https://drafts.csswg.org/css-text-3/#propdef-white-space

閑話休題。

Hexo には、この問題を解決するためのプラグインがあります。
https://github.com/lotabout/hexo-filter-fix-cjk-spacing

導入は簡単で、単に NPM パッケージをインストールするだけです。

$ npm install hexo-filter-fix-cjk-spacing --save

あとは普通に hexo server とか hexo generate とか hexo deploy とかすれば、自動的に日本語文字間の改行を削除してくれます。原稿(Markdown ソースファイル)には手を加える必要がありません。

作者の Jinzhou Zhang さん に感謝!

なお、この記事の話は _config.ymlbreaks: false を指定している前提です。 breaks: true の場合はそもそも「ソースファイルの改行をそのまま反映してください」という意味になるので、ソースファイルの改行ごとに自動的に HTML の <br /> 要素が追加されます。

Perl めも

導入

$ \curl -L https://install.perlbrew.pl | bash
$ echo 'source ~/perl5/perlbrew/etc/bashrc' >> ~/.bashrc
$ bash
$ perlbrew list
$ perlbrew available
$ perlbrew available | grep -E '^  perl-5\.[1-9]?[02468]\.' | nice -19 xargs -n 1 perlbrew install
$ perlbrew list
$ perlbrew switch perl-5.24.1
$ perl -v
$ perlbrew install-cpanm

アップデート

$ perlbrew self-upgrade

CPAN モジュールのローカルインストール

$ cpanm -L lib URL::Encode

おやくそく

#!/usr/bin/env perl

use strict;
use warnings;
use utf8;

use lib './lib/lib/perl5';

use Carp qw/confess/;

use Data::Dumper;
$Data::Dumper::Purity = 1;

定数を使う

http://d.hatena.ne.jp/fbis/20090612/1244806476

use constant DNS_SERVER_LIST => [
    '8.8.8.8',          # Google Public DNS
    '8.8.4.4',          # Google Public DNS
    ''                  # default
];
use constant DNS_ROUND_ROBIN_LIMIT => 10;

my @result;
foreach my $server (@{DNS_SERVER_LIST()}) {
    push(@result, nslookup($fqdn, $server, DNS_ROUND_ROBIN_LIMIT));
}

Encode モジュールの罠

Encode::encode()Encode::decode() で第3引数に Encode::FB_CROAK を指定すると、第2引数に指定した文字列を破壊するらしい。

CAVEAT: the input scalar STRING might be modified in-place depending on what is set in CHECK.

したがって、次のようにやると元の文字列 @nslookup_raw が破壊されます。実際には、長さゼロの文字列の配列になってしまいました。

my @nslookup_raw = `nslookup -type=A $host 2>&1`;
my @nslookup =
    map {s/\r?\r\n$/\n/; $_}
    map {use Encode qw/decode/; decode("shiftjis", $_, Encode::FB_CROAK)}
    @nslookup_raw;

とりあえず次のように定義して使うのが安全っぽい。

sub decode {
    use Encode qw//;
    return Encode::decode("shiftjis", shift, Encode::FB_CROAK | Encode::LEAVE_SRC);
}

sub encode {
    use Encode qw//;
    return Encode::encode("UTF-8", shift, Encode::FB_CROAK | Encode::LEAVE_SRC);
}

半角カナを全角カナに変換

sub hankaku2zenkaku {
    use Lingua::JA::Regular::Unicode;
    return katakana_h2z(shift);
}

encodeURIComponent

sub encode_uri_component {
    use URL::Encode qw//;
    return URL::Encode::url_encode_utf8(shift);
}