Sphinxのテーブルで全角記号を使いたい-sphinxcon-jp-2018

A8d671a89be160a7b90a0bccebe31c79?s=47 anzawatta
November 28, 2018

 Sphinxのテーブルで全角記号を使いたい-sphinxcon-jp-2018

A8d671a89be160a7b90a0bccebe31c79?s=128

anzawatta

November 28, 2018
Tweet

Transcript

  1. Sphinxのテーブルで 全角記号を使いたい SphinxCon JP 2018 2018/11/28 @anzawatta

  2. 自己紹介 • anzawatta – 普段はPHPer – Pythonで趣味ツール作成 – Sphinx+Ablogでブログ •

    生息地 – Twitter: @anzawatta – Blog: anzawatta-blog 1
  3. 概要 • テーブルに全角記号が含まれるとエラー になることについて • 原因、East Asian Widthについて • 対処方法について

    2
  4. エラー発生 • 全角記号を含むグリッドテーブルを作成 +-------+ | ◦あa | +-------+ ビルド時にエラー発生 Malformed

    table. 3 ◦あa 作成文章 ビルド結果予想
  5. Malformed table • テーブルのセル枠とセル内容の文字数が異な ると発生 +-------+ | 123 | +-------+

    作成するエディタでは揃っているように見える (全角1文字は半角文字2つ分) +-------+ | ◦あa | +-------+ 4
  6. エラーの発生部分 • Docutilsのテーブルパース部分 – rst/states.py Body::isolate_grid_table() – 最初のテーブル枠の長さと異なるとエラー – +|

    が存在しないとエラー 全角文字は半角文字2つ分では? 5
  7. 全角文字の取り扱い • テーブルの長さ取得 – statemachine.py StringList::pad_double_width() – east_asian_width(char) == ‘WF’なら全角文

    字と判断 6 new = [] for char in line: new.append(char) if east_asian_width(char) in 'WF': # 'W'ide & 'F'ull-width new.append(pad_char) self.data[i] = ''.join(new)
  8. 全角記号をパース • テーブルをパースした結果 – あ の後ろにpad_char ¥x00 が付与 – 半角2文字分としてカウント

    ◦ は全角として扱われない unicodedata.east_asian_width(‘◦’) == ‘A’ 7 +-------+ | ◦あa | +-------+ 入力文 ['+------+', '| ◦あ¥x00a |', '+------+'] パース結果
  9. East Asian Width • Unicodeで文字幅がどの横幅になるかの分類 – Fullwidth(F: !,A) – Halfwidth(H:

    ア,ァ) – Wide(W: あ,ア,一) – Narrow(Na: A,0) – Ambiguous(A: ,◦) – Neutral(N: À,©) • Pythonで判断 – unicodedata.east_asian_width() 8
  10. East Asian Widthの割合 9 U+0000~U+10FFFF (未割当含む、サロゲートペア以外)の割合 Fullwidth: 853963(76.65%) Halfwidth: 123(0.01%)

    Wide: 95360(8.56%) Narrow: 111(0.01%) Ambigous: 138746(12.45%) Neutral: 23761(2.13%) F A W
  11. Ambiguousの扱い UAX(A Unicode Standard Annex) #11で推奨 されている分類 Docutilsの全角判断(W or F)と異なる

    10 Fullwidth Halfwidth Wide Narrow Ambiguous Neutral 東アジア 全角 半角 全角 半角 全角 半角 東アジア 以外 半角 半角 半角
  12. • 全角文字判断の条件に A を追加 – statemachine.py StringList::pad_double_width() new = []

    for char in line: new.append(char) if east_asian_width(char) in 'WAF': new.append(pad_char) self.data[i] = ''.join(new) 対処法 11
  13. 修正結果 • 全角記号もエラーなしで出力可 +-------+ | ◦あa | +-------+ Docutilsをべた書きで修正してしまう… 12

    ◦あa
  14. 問題点 • ドキュメントを書く環境によってはエラーが 発生 – ロケールをjaから変えると「◦」の幅は1 – フォントをConsolasにすると「◦」の幅は1 ロケールやフォントの設定をコメントしておけば 良い…?

    13 MigMix 1M(ja_JP) Consolas(C) MigMix 1M(C)
  15. 解決かと思いきや • 全てAmbiguousな全角記号に見えるが… +----------+ | ♠♣♥♦ | +----------+ Malformed table.

    ♦ だけはN(Neutral)なので横幅1文字 他にも、◐(U+25d0)はAだが ◒(U+25d2)はN …等々 14 ♠: U+2660 ♣: U+2663 ♥: U+2665 ♦: U+2666
  16. Sphinx拡張を作る(未完) • テーブル枠とセル内の長さが違ってもエラーにな らないテーブルの文法を追加 – https://gist.github.com/anzawatta/803b648d83db26df040d919 540936eb6 ^-------^ | ◦あa

    | ^-------^ • doctree-resolvedで新テーブルをパース 15 • テーブルの要素 – 両端: ^ – セルの横枠: - – セルの縦枠: | • ルール – 枠の両端は必ず ^ – セルの両端は必ず |
  17. Sphinx拡張を作ってみた • 枠のチェック、<table>作成はできた – <td>がないのでテーブル表示にならない – 上下の枠なしでもいいのでは 16 入力テキスト ビルド結果

    ビルド結果のソース
  18. まとめ • 全角記号をテーブルに使うのは難しい • Docutilsは取っつきにくい – To be completed. –

    Use the Source, Luke! • Sphinx拡張は触ってみると面白い 17
  19. 参考 • プログラマのための文字コード技術入門 • UAX #11 – http://www.unicode.org/reports/tr11 • 文字コード地獄秘話

    – http://tech.alvert2005.co.jp/81 • methaneのブログ – https://methane.hatenablog.jp/entry/20070 109/1168316594 • マスタリングdocutils 18