Unicodeのすべての文字を1回ずつ使って絵を描く

文字の並びで表現された絵は一般にアスキーアートと呼ばれます。その名前からは、使える文字がASCII文字に制限されているように思えますが、実際はそうではなく、なんでもありです。「MS Pゴシック」に含まれる文字を使うのが伝統でしょうか。

先日数えてみたように、Unicode 6.0にはGraphic Characterが109242個あります(参照:Unicodeのすべての文字を1ページで)。使える文字をここまで広げると、いわゆるアスキーアートのように文字の形を利用するのではなく、文字の濃さを利用して絵を描けます。(Graphic Charactersに印刷できない文字も含まれていることは、ここでは無視します。)

せっかくこれだけの文字があるので、それぞれの文字は1回しか使えないという制約を入れましょう。正方形のキャンバスなら、331 × 331のグリッド上に文字を並べることになります(331 x 331 = 109561は109242以上の最小の平方数)。ちょっと文字が足りないので、その分は半角スペースで補うことにします(109561 – 109242 = 319個)。

こんな絵が描けます(クリックで拡大、PDF 23MB)。

Unicodeのすべての文字を1ページで

この記事で作るもの:Unicode 6.0のすべての文字を1ページで (PDF, 23MB)

4327377368ヨハネス・ベルガーハウゼン, シリ・ポアランガン『世界の文字と記号の大図鑑 ー Unicode 6.0の全グリフ』(研究社, 2014)の著者はUnicode 6.0の全109242文字2時間30分かけて見るビデオの作者ですか。今度は1024ページの書籍。「Decodeunicode」で画像検索すると原著が出てきますが、楽しみですね。(追記:世界の文字と記号の大図鑑

「Unicodeのすべての文字を印刷した本って、前にもなかったっけ?」と思って本棚を探したのですが、勘違いでした。

0321480910頭に浮かんだのはThe Unicode Consortium『The Unicode Standard, Version 5.0』(Addison-Wesley Professional, 2006)(文献リストあり、索引なし)だったのですが、この本は、(1) The Unicode Standard、(2) Code Charts (PDF)から漢字を除いたもの、(3) Han Radical-Stroke Index (PDF)という構成でした。つまり、漢字はコードポイント順に一つずつではなく、Han Radical-Stroke Indexという形で掲載されているだけでした。

Unicode 5.0より後は、紙媒体ではないようですが、たとえば6.0について同じことをするなら、 (1) The Unicode Standard (PDF)、(2) Code Charts (PDF)、(3) Han Radical-Stroke Index (PDF)を使うことになるのでしょう。(Code Chartsには漢字も含まれているので、「文字の一覧(番号順)」が欲しいだけならCode Chartsだけで十分です。)

これらの資料もいいのですが、こういうのは、自分でもちょっとやってみたいところです。例えば、Unicodeの全文字を1ページに、なんてことも、自分で作れるようになればできます。

というわけで、必要なデータをEnumerated Versions of The Unicode Standardから探して作ろうとしたら、これがなかなか面倒でした。

Unicode 6.0の全文字は、UnicodeData.txtに載っているはずですが、この第1列をHTMLの数値文字参照に置き換えるだけでは終わりません。

UnicodeData.txtには、CJK統合漢字など、1行1文字になっていない部分があります。それを補うのは面倒なので、Unicode 5.1以降で導入されたUnicode Character
Database in XML
を使うことにします。このXMLファイルは、char要素1個が1文字に対応します。

XMLファイルには、印刷できない文字?も含まれているので、それを除外しなければなりません。Unicode 6.0のコードポイントは109449個ありますが、そのうちGraphic Characterは109242個です(参照)。『世界の文字と記号の大図鑑』の109242文字というのはこれのことなのでしょう。Graphic Characterの定義General_Category ValuesThe Unicode Standard Chapter 2 General Structureの「Table 2-3. Types of Code Points」を見ると、char要素のgc属性値がCから始まるものとZl, Zpになっているものは除外しなければならないことがわかります。(異体字セレクタのような、明らかに印刷不能な文字が残るのですが、とりあえずはそのままにします。それを使う異体字もここでは数えません。)

というわけで、ちょっとスクリプトを書いて、Unicode 6.0の文字の一覧を作ります。

こんなHTMLファイルです。このファイルは、Unicodeの文字を数値文字参照で書いてあるだけのものなので、文字を実際に表示できるかどうかは環境によります。Noto花園明朝などを入れた環境で、Firefox 31とChrome 36を試したところ、FirefoxはUnicode 6.0のすべての字形を表示できたようですが、Chromeはぜんぜんだめでした(目視以外の確認法がわかりません)。

Windows上のFirefoxでAdobe PDFに印刷した結果が冒頭のPDFファイルです。

完成に必要な無料フォントを列挙する(あるいはもっとよい方法の提案)という自由研究を、どこかの小学生がやってくれることを期待します。

関連:Unicodeのすべての文字を1回ずつ使って絵を描く

追記:The Unicode Map Projectがすばらしいです。

フリーソフトウェアで風景から歩行者を消す方法(FFmpeg, ImageMagick)

先日「風景から歩行者を消す手軽な方法」をMathematicaで実装したのですが、「なんでMathematica? 持ってないし。高いじゃん」という意見があったので、フリーソフトウェアを使う方法を紹介しましょう。「風景から歩行者が消えていく様子」が要らないならこれで十分かも知れません。(Raspberry PiのMathematicaなら無料なのですが、非力なのでこの話には使いにくいでしょう。)

Ubuntuで試します。(WindowsでもFFmpegとImageMagickを入れればできるかもしれません。)

sudo apt-get install libav-tools imagemagick

ffmpegで動画を画像に分解し、convertでまとめます。(Ubuntu 14.04ではffmpegavconvに置き換えてください。)

ffmpeg -i movie.mov -f image2 %d.png
convert -evaluate-sequence mean *.png mean.jpg

meanmedianに置き換えれば平均ではなく中央値を使うようになりますが、処理時間がかなり増えます。

ディレクトリ内のテキストファイルの総行数を求めるには

はじめに結論ですが、

grep -rI '' foo|wc -l

がいいと思います。

次のようなスクリプトで作られるディレクトリで試しましょう。UbuntuのshのechoやBSD echo(Macの/bin/echo)ではなく、bashのechoを使ってください。

#!/bin/bash
rm -r foo
rm b
mkdir -p foo/bar
mkdir -p foo/.baz

echo -n 1 > foo/a
echo 2 > 'foo/b b'
echo 3 > foo/.c
echo -e '456\n\n\n\n8' > foo/bar/d
echo 9 > foo/.baz/e
echo -en '\x00' > foo/f
echo -en '\x00' > foo/g
echo -en '\x00' > foo/h
echo -en '\x00' > foo/i

上のスクリプトで作られるディレクトリfooには、テキストファイルが5つあり、行数の合計は9(空行を無視すると6)になります。

ディレクトリ内のテキストファイルの総行数を求める方法をネットで探すといろんな説が見つかりますが、一つずつ試してみましょう。(参考:ファイルの行数を数えるのは「wc -l file」ではありません

find foo -type f | xargs wc -l

結果は7(間違い。ファイル名に空白が含まれる場合に未対応)

find foo -type f -print0 | xargs -0 wc -l

結果は8(間違い。ファイルの末尾が改行でないいときに未対応)

find foo -type f -print0 | xargs -0 awk 'END{print NR}'

結果は13(間違い。バイナリファイルの処理が不適切)

grep -r . foo | wc -l

結果は10(間違い。バイナリファイルの処理が不適切)

grep -rI . foo | wc -l

結果は6(間違い。空行を無視するならこれでよい)

grep -rI '' foo | wc -l

結果は9(正解)

shopt -s dotglob; grep -rI '' foo/* | wc -l; shopt -u dotglob

結果は9(bash限定だが正解)

おまけ:特定のディレクトリを除外したいとき

mkdir -p foo/foo/.baz
echo 10 > foo/foo/.baz/10
mkdir foo/abaz
echo 11 > foo/abaz/11

.bazという名前のディレクトリをすべて除外したいときは、

grep -rI '' foo | grep -v '/\.baz/' | wc -l

比較的新しいgrepなら次のようにも書けます。

grep -rI '' --exclude-dir='\.baz' foo | wc -l

ディレクトリfoo/.bazだけを除外して、foo/foo/.bazは除外しないときは、

grep -rI '' foo | grep -v '^foo/\.baz/' | wc -l

ファイルの行数を数えるのは「wc -l file」ではありません

wc -l file」が数えるのは行数ではなく改行数なので、ファイルの末尾が改行でない場合、行数よりも1少ない結果が返ります(GNU wc・BSD wcともに)。

4行(空行を無視すると2行)からなるファイルfooを作って確かめます。UbuntuのshのechoやBSD echo(Macの/bin/echo)ではなく、bashのechoを使ってください。

#!/bin/bash
echo -en '123\n\n\n3' > foo
wc -l foo
cat foo | wc -l
awk 'END{print NR}' foo
grep . foo | wc -l
grep '' foo | wc -l

結果は下のとおり。

3 foo
3
4
2
4

行数を数えたいときは「grep '' file|wc -l」や「awk 'END{print NR}' file」、空行を無視したいときは「grep . file|wc -l」でしょうか。

続き:ディレクトリ内のテキストファイルの総行数を求めるには