2020/11/28
ここでは python-docx において下線・傍点・フリガナを扱う方法
およびそのサンプルスクリプトについて記します。
python-docxは、ワード文書(docxファイル)を処理するためのpythonライブラリです。
docxファイルの中核をなすxmlを処理することによってファイルの生成や変更を行います。
Windows上でワードを起動したりはしないので、 OSに依存せずpythonが動作する環境であれば使えます。
下線については paragraph を構成するrunオブジェクトに対して
run.underline = True
とすれば付加できますが、
点線の下線とか二重線の下線を指定することはできません。
ここでは、そうした指定ができる方法について記します。
python-docxは、その利用者がxmlのソースを意識することなく 簡単に処理できるよう工夫されていますが、その工夫の対象外の事柄を扱うときは xmlソースを意識した処理にならざるを得ません。
なので、基本的な構成要素のxml表現を記しておきます。
<w:p> …… </w:p>
<w:r> …… </w:r>
<w:rPr> …… </w:rPr>
フリガナを扱うための構成要素は少々複雑なので後述します。
まず下線にかかわるxmlソースについて述べ、
その後にpythonスクリプトを掲げます。
下線にかかわるxmlは次の1行です。
<w:u w:val="single"/>
上をrPrの中に盛り込みます。
single を double にすれば二重下線になり、dot にすれば点線の下線になります。
下線を含むrunのxmlソースを下に掲げておきます。
「あいうえお」に下線が付く例です。
<w:r>
<w:rPr>
<w:u w:val="double"/>
</w:rPr>
<w:t>あいうえお</w:t>
</w:r>
「名前は山内といいます。」というparagraphを生成しますが、
「山内」に下線を引きます。
なので、paragraphは「名前は」 「山内」 「といいます。」の
三つのrunから構成されることになります。
スクリプトでは、次の二つの関数を定義しています。
make_normal_run(text)
make_u_run(text, type)
"single"
とか "double"
のような下線の種類を指定するものです。以下、スクリプト underline.py です。
# encoding: utf-8
import docx
from docx.oxml import OxmlElement
# アンダーラインのrunを生成
def make_u_run(text, type = "single"):
new_run = OxmlElement('w:r')
rPr = OxmlElement('w:rPr')
u = OxmlElement('w:u')
u.set(docx.oxml.shared.qn('w:val'), type)
rPr.append(u)
new_run.append(rPr)
new_run.text = text
return new_run
# 通常のrunを生成
def make_normal_run(text):
new_run = OxmlElement('w:r')
new_run.text = text
return new_run
## main
document = docx.Document()
document.add_paragraph('アンダーラインのテスト.')
p = document.add_paragraph()
new_run = make_normal_run("名前は")
p._p.append(new_run)
new_run = make_u_run("山内", "double")
p._p.append(new_run)
new_run = make_normal_run("といいます。")
p._p.append(new_run)
document.save('underline.docx')
下線の種類は、私が把握した範囲では 17種類あります。
下線を消去するための none を入れると18種類です。
以下にその一覧を掲げます。
xml値(xmlにおける書き方)のほかに、定数値と定数名も記します。
定数値(整数)と定数名は VBAで用いるものですが、
拙作 usepandoc.py で下線の種類を指定するときは定数値を使います。
たとえば下のとおり。
名前は#u3{山内}といいます。
xml値 | 定数値 | 定数名 |
---|---|---|
none | 0 | wdUnderlineNone |
single | 1 | wdUnderlineSingle |
words | 2 | wdUnderlineWords |
double | 3 | wdUnderlineDouble |
dotted | 4 | wdUnderlineDotted |
thick | 6 | wdUnderlineThick |
dash | 7 | wdUnderlineDash |
dotDash | 9 | wdUnderlineDotDash |
dotDotDash | 10 | wdUnderlineDotDotDash |
wave | 11 | wdUnderlineWavy |
dottedHeavy | 20 | wdUnderlineDottedHeavy |
dashedHeavy | 23 | wdUnderlineDashHeavy |
dashDotHeavy | 25 | wdUnderlineDotDashHeavy |
dashDotDotHeavy | 26 | wdUnderlineDotDotDashHeavy |
wavyHeavy | 27 | wdUnderlineWavyHeavy |
dashLong | 39 | wdUnderlineDashLong |
wavyDouble | 43 | wdUnderlineWavyDouble |
dashLongHeavy | 55 | wdUnderlineDashLongHeavy |
傍点を付ける方法は、基本的に下線の場合と同じです。
xmlの表現でいうと下のとおり。
<w:em w:val="dot"/>
下線の w:u
を w:em
に変更すれば傍点の指定になります。
なので、xmlソースに関する説明は省略して、
スクリプトと、指定できる傍点の種類について記します。
「今日の天気は雨天でした。」というparagraphを生成しますが、
「雨天」に傍点を付けます。
「雨天」とその前後で分かれるので、合計三つのrunになります。
以下、スクリプト EmphasisMark.py です。
# (encoding: utf-8)
import docx
from docx.oxml import OxmlElement
# 傍点のrunを生成
def make_em_run(text, type = "dot"):
new_run = OxmlElement('w:r')
rPr = OxmlElement('w:rPr')
em = OxmlElement('w:em')
em.set(docx.oxml.shared.qn('w:val'), type)
rPr.append(em)
new_run.append(rPr)
new_run.text = text
return new_run
# 通常のrunを生成
def make_normal_run(text):
new_run = OxmlElement('w:r')
new_run.text = text
return new_run
## main
document = docx.Document()
document.add_paragraph('傍点のテスト.')
p = document.add_paragraph()
new_run = make_normal_run("今日の天気は")
p._p.append(new_run)
new_run = make_em_run("雨天", "circle")
p._p.append(new_run)
new_run = make_normal_run("でした。")
p._p.append(new_run)
document.save('EmphasisMark.docx')
傍点の種類は、私が把握した範囲では 4種類あります。
傍点を消去するための none を入れると5種類です。
以下にその一覧を掲げます。
xml値 | 定数値 | 定数名 |
---|---|---|
none | 0 | wdEmphasisMarkNone |
dot | 1 | wdEmphasisMarkOverSolidCircle |
comma | 2 | wdEmphasisMarkOverComma |
circle | 3 | wdEmphasisMarkOverWhiteCircle |
underDot | 4 | wdEmphasisMarkUnderSolidCircle |
まずフリガナにかかわるxmlソースについて述べ、
その後にpythonスクリプトを掲げます。
ちなみに、xmlではフリガナを ruby(ルビ)と表現し、
VBAでは PhoneticGuide と表現するようです。
「山内」に対して「ヤマノウチ」というフリガナを付ける場合を考えます。
構成要素の小さい方から述べます。
まず「山内」という漢字本体を格納したrunを用意します。
それとは別に「ヤマノウチ」というフリガナを格納したrunも用意します。
次に、漢字本体のrunを rubyBase という要素に格納し、
フリガナのrunは rt という要素に格納します。
そして、rubyという要素に rt および rubyBase を格納します。
漢字本体よりフリガナの方を先に配置するのが標準のようです。
最後に、rubyという要素を大きなrunに格納します。
この大きなrunが paragraph の構成要素になります。
xmlソースの形で示すと次のとおり。
<w:r>
<w:ruby>
<w:rt>
<w:r>
<w:t>ヤマノウチ</w:t>
</w:r>
</w:rt>
<w:rubyBase>
<w:r>
<w:t>山内</w:t>
</w:r>
</w:rubyBase>
</w:ruby>
</w:r>
インデントをつけているのは、各要素の含む・含まれるの関係を示すためです。
元のxmlソースには余分なスペースも改行もなくだらだら連続しています。
また、上は最も単純化したxmlソースです。
フリガナなどにプロパティを付けていません。
なので、デフォルトのプロパティが適用されるとおもいます。
「名前は山内といいます。」というparagraphを生成します。
「山内」に「ヤマノウチ」というフリガナを付けます。
以下、スクリプト ruby.py です。
# (encoding: utf-8)
import docx
from docx.oxml import OxmlElement
# フリガナ設定したrunを生成
def make_ruby_run(baseText, rubyText):
base_run = OxmlElement('w:r')
ruby_run = OxmlElement('w:r')
base_run.text = baseText
ruby_run.text = rubyText
ruby = OxmlElement('w:ruby') # 本体&フリガナの入れ物
rt = OxmlElement('w:rt') # フリガナの入れ物
rt.append(ruby_run)
rubyBase = OxmlElement('w:rubyBase') # 本体の入れ物
rubyBase.append(base_run)
ruby.append(rt)
ruby.append(rubyBase)
new_run = OxmlElement('w:r')
new_run.append(ruby)
return new_run
# 通常のrunを生成
def make_normal_run(text):
new_run = OxmlElement('w:r')
new_run.text = text
return new_run
## main
document = docx.Document()
document.add_paragraph('フリガナのテスト.')
p = document.add_paragraph()
new_run = make_normal_run("名前は")
p._p.append(new_run)
new_run = make_ruby_run("山内", "ヤマノウチ")
p._p.append(new_run)
new_run = make_normal_run("といいます。")
p._p.append(new_run)
document.save('ruby.docx')
~ 以上 ~
Copyright (C) T. Yoshiizumi, 2019-2020 All rights reserved.