読者です 読者をやめる 読者になる 読者になる

Python 3で絵文字を羅列する


このエントリーをはてなブックマークに追加

Python3を使って、Unicodeに登録された絵文字を羅列して遊んでみました。この記事ではPython 3でのみ動作確認をしています。

コードポイントから文字への変換

Pythonの組み込み関数であるchr()を使うと、Unicodeのコードポイント(日本語では符号点)から文字への変換ができます。

import unicodedata
print(chr(97)) # 'a'
print(chr(12354)) # 'あ'

Unicodeのコードポイントは現時点でU+10FFFFまで存在するので、これを総当りするとすべての文字が羅列できます。

for i in range(0, 0x110000):
    ch = chr(i)

カテゴリ別に文字を分類

標準ライブラリであるunicodedataを使うと、文字の名前やカテゴリーなどを取得できます。

import unicodedata
print(unicodedata.name('あ'))  # 'HIRAGANA LETTER A'
print(unicodedata.category('あ')) # 'Lo'

カテゴリーの説明は例えば Unicode Character Categories で確認できます。'Lo'カテゴリーは'Letter, Other'という意味だそうです。

カテゴリー別の文字数を以下のコードで数え上げることができます。対した量ではないので数秒で完了します。

from collections import defaultdict
import unicodedata

# reference: http://www.fileformat.info/info/unicode/category/index.htm 
category_meanings = {
    'Cc' : 'Other, Control',
    'Cf' : 'Other, Format',
    'Cn' : 'Other, Not Assigned (no characters in the file have this property)',
    'Co' : 'Other, Private Use',
    'Cs' : 'Other, Surrogate',
    'LC' : 'Letter, Cased',
    'Ll' : 'Letter, Lowercase',
    'Lm' : 'Letter, Modifier',
    'Lo' : 'Letter, Other',
    'Lt' : 'Letter, Titlecase',
    'Lu' : 'Letter, Uppercase',
    'Mc' : 'Mark, Spacing Combining',
    'Me' : 'Mark, Enclosing',
    'Mn' : 'Mark, Nonspacing',
    'Nd' : 'Number, Decimal Digit',
    'Nl' : 'Number, Letter',
    'No' : 'Number, Other',
    'Pc' : 'Punctuation, Connector',
    'Pd' : 'Punctuation, Dash',
    'Pe' : 'Punctuation, Close',
    'Pf' : 'Punctuation, Final quote (may behave like Ps or Pe depending on usage)',
    'Pi' : 'Punctuation, Initial quote (may behave like Ps or Pe depending on usage)',
    'Po' : 'Punctuation, Other',
    'Ps' : 'Punctuation, Open',
    'Sc' : 'Symbol, Currency',
    'Sk' : 'Symbol, Modifier',
    'Sm' : 'Symbol, Math',
    'So' : 'Symbol, Other',
    'Zl' : 'Separator, Line',
    'Zp' : 'Separator, Paragraph',
    'Zs' : 'Separator, Space'
}

category_to_chars = defaultdict(list)
for i in range(0, 0x110000):
    ch = chr(i)
    category = unicodedata.category(ch)
    category_to_chars[category].append(ch)

for category in sorted(category_to_chars, key=lambda x: -len(category_to_chars[x])):
    print("{} ({}): {}".format(
        category,
        category_meanings[category],
        len(category_to_chars[category])))

結果は以下の通りです。

Cn (Other, Not Assigned (no characters in the file have this property)): 864409
Co (Other, Private Use): 137468
Lo (Letter, Other): 97553
So (Symbol, Other): 4404
Cs (Other, Surrogate): 2048
Ll (Letter, Lowercase): 1751
Lu (Letter, Uppercase): 1441
Mn (Mark, Nonspacing): 1281
Sm (Symbol, Math): 948
No (Number, Other): 464
Nd (Number, Decimal Digit): 460
Po (Punctuation, Other): 434
Mc (Mark, Spacing Combining): 352
Lm (Letter, Modifier): 237
Nl (Number, Letter): 224
Cf (Other, Format): 145
Sk (Symbol, Modifier): 115
Ps (Punctuation, Open): 74
Pe (Punctuation, Close): 73
Cc (Other, Control): 65
Sc (Symbol, Currency): 49
Lt (Letter, Titlecase): 31
Pd (Punctuation, Dash): 23
Zs (Separator, Space): 17
Pi (Punctuation, Initial quote (may behave like Ps or Pe depending on usage)): 12
Me (Mark, Enclosing): 12
Pc (Punctuation, Connector): 10
Pf (Punctuation, Final quote (may behave like Ps or Pe depending on usage)): 10
Zp (Separator, Paragraph): 1
Zl (Separator, Line): 1

絵文字を含む文字を羅列

上記カテゴリーのうち、'So (Symbol, Other)'カテゴリーはEmoji - Wikipediaを含むなどもっともカオスで見応えがあるので、このカテゴリーの文字を羅列してみます。上記のコードに続いて以下のコードを加えます。文字化けのしにくいChromeなどのブラウザでの表示を期待して、50文字ごとに改行タグを挿入しています。

CHAR_PER_LINE = 50
for i, ch in enumerate(category_to_chars['So']):
    print(ch, end="")
    if (i + 1) % CHAR_PER_LINE == 0:
        print("<br>")

一部のスクリーンショットを以下に示します。ドミノ、麻雀牌、トランプ、野球記号などが入り乱れていて驚きの連続です。 f:id:minus9d:20161208230332p:plain 出力結果の全部はunicode 'So' categoryで確認できます。

表形式での表示

unicodedata.name()を使うと文字の名前を知ることができます。以下のコードは、文字とその名前をテーブルで出力します。

print("<table border=\"1\">")
print("<tr><td>Char<td>Code Point<td>Name</tr>")
for ch in category_to_chars['So']:
    print("<tr><td>{}<td>{}(U+{:X})<td>{}</tr>".format(
        ch, ord(ch), ord(ch), unicodedata.name(ch)))
print("</table>")

部分を抜き出すと、以下のような感じで表示できます。

Char Code Point Name
9848(U+2678) RECYCLING SYMBOL FOR TYPE-6 PLASTICS
9849(U+2679) RECYCLING SYMBOL FOR TYPE-7 PLASTICS
9850(U+267A) RECYCLING SYMBOL FOR GENERIC MATERIALS
9851(U+267B) BLACK UNIVERSAL RECYCLING SYMBOL
9852(U+267C) RECYCLED PAPER SYMBOL
9853(U+267D) PARTIALLY-RECYCLED PAPER SYMBOL
9854(U+267E) PERMANENT PAPER SIGN
9855(U+267F) WHEELCHAIR SYMBOL
9856(U+2680) DIE FACE-1
9857(U+2681) DIE FACE-2

ブラウザに表示されるテーブルをコピペしてunicode 'So' category tableに載せました。

コード全文

unicode_bruteforce.py