Pythonで実行する【アウトライン・プロセッサー】コメント削除機能あり
トマトジュー酢
実況プログラミング
プログラムは読める、でも書けない、自信がない、という方に捧げる、実況プログラミングを行います。
お題は、アウトライン・プロセッサーの作成です。
アウトライン・プロセッサーとは、見出しと連携したテキストを合成する処理です。
小説や論文作成で使われています。
なんと言っても、編集が自由自在です。
場面1
場面2
場面3
の見出しの並びに
場面1
場面1-1
場面2
場面3
とか
場面1
場面3
とか、本文の編集が数行の操作で実現できます。
作ろうと思い立ったのは、当方ポメラの古い機種で小説を書いていて、場面編集がいちいちファイルを開いてコピペが面倒、というわけで始めます。
さて、目標が定まったので、仕様を決めます。
テキストファイルの先頭行は見出しとします。
本文から見出しを引用する方法は、
[見出し]
[ 見出し ]
など、半角のカッコを見出し指示とします。
階層構造にも対応します。
それ以外は、本文でそのまま出力します。
ただし、行頭に半角#がある行は、コメントとみなして出力しません。
# コメントだよ
実行ディレクトリに存在する拡張子がtxtのファイルは、見出しを含むとみなします。
つまり、拡張子がtxtのファイルを全て読み込みます。
これで、仕様が完成しました。
プログラムを組む前に、仕様を詰めるのはとても大事です。
さて、プログラミングを始めましょう。
まずは、日本語のファイルを読み込まなければなりません。
python utf8 で調べるとcodecsというモジュールを使えばいいことがわかりました。
さっそく、webのサンプルプログラムをコピペして作成します。
------------ outliner.py
# coding:utf-8
# run on python2.7x
import codecs
import sys
class Context:
def __init__(self, filename):
f = codecs.open(filename, 'r', 'utf-8')
self.lines_ = f.readlines()
f.close()
print len(self.lines_)
for l in self.lines_:
print l
if 1 < len(sys.argv):
root = Context(sys.argv[1])
------------ root.txt
てすと
# コメントだよ
[ 操縦士訓練学校を受験する ]
[ 初任務 ]
[ 初任務a ]
------------
root.txtを引数に実行すると、期待通りに本文が読み込まれました。
次は、実行ディレクトリに存在する拡張子がtxtのファイルを列挙して読み込みます。
ファイルの読み込みは、Contextクラスで対応したので、ファイルを列挙をする方法を調べます。
python ファイル 列挙 で調べるとglobというモジュールを使えばいいことがわかりました。
------------ outliner.py
# coding:utf-8
# run on python2.7x
import codecs
import sys
import glob
class Context:
def __init__(self, filename):
f = codecs.open(filename, 'r', 'utf-8')
self.lines_ = f.readlines()
f.close()
def dump(self):
for l in self.lines_:
print l
if 1 < len(sys.argv):
root = Context(sys.argv[1])
filenames = glob.glob('*.txt')
for filename in filenames:
print filename
a = Context(filename)
a.dump()
------------
期待通りに、拡張子がtxtのファイルを読み込めました。
次は、各ファイルの先頭行、つまり見出しを出力してみます。
------------ outliner.py
# coding:utf-8
# run on python2.7x
import codecs
import sys
import glob
class Context:
def __init__(self, filename):
f = codecs.open(filename, 'r', 'utf-8')
self.lines_ = f.readlines()
f.close()
def dump(self):
for l in self.lines_:
print l
def line(self, n = 0):
if len(self.lines_) <= n:
return None
return self.lines_[n].rstrip()
if 1 < len(sys.argv):
root = Context(sys.argv[1])
filenames = glob.glob('*.txt')
for filename in filenames:
a = Context(filename)
k = a.line()
if k is None:
pass
elif 0 < len(k):
print k
------------
期待通りに、先頭行の見出しを出力できました。
次は、見出しでファイルを管理します。
具体的には、
contexts[見出し] = Context()
で見出しからファイルを辿れるようにします。
------------ outliner.py
# coding:utf-8
# run on python2.7x
import codecs
import sys
import glob
class Context:
def __init__(self, filename):
f = codecs.open(filename, 'r', 'utf-8')
self.lines_ = f.readlines()
f.close()
def dump(self):
for l in self.lines_:
print l
def line(self, n = 0):
if len(self.lines_) <= n:
return None
return self.lines_[n].rstrip()
if 1 < len(sys.argv):
contexts = {}
root = Context(sys.argv[1])
filenames = glob.glob('*.txt')
for filename in filenames:
a = Context(filename)
k = a.line()
if k is None:
pass
elif 0 < len(k):
contexts[k] = a
for k, v in contexts.items():
print k
------------
期待通りに、見出しからファイルを引用することができました。
次は、本プログラムの最も重要な処理を作成します。
本文中の見出し引用指示をみつけます。
以下のプログラムでは、headline()がその処理にあたります。
------------ outliner.py
# coding:utf-8
# run on python2.7x
import codecs
import sys
import glob
class Context:
def __init__(self, filename):
f = codecs.open(filename, 'r', 'utf-8')
self.lines_ = f.readlines()
f.close()
def dump(self):
for l in self.lines_:
print l
def line(self, n = 0):
if len(self.lines_) <= n:
return None
return self.lines_[n].rstrip()
def headline(self, n):
l = self.line(n)
if l is None:
return None
if len(l) <= 0:
return None
h = l.lstrip()
if h[0] == '[' and h[-1] == ']':
return h[1:-1]
return None
if 1 < len(sys.argv):
contexts = {}
root = Context(sys.argv[1])
stack = [[root.line(), 1]]
filenames = glob.glob('*.txt')
for filename in filenames:
a = Context(filename)
k = a.line()
if k is None:
pass
elif 0 < len(k):
contexts[k] = a
while len(stack):
cur = stack[-1]
k = cur[0]
n = cur[1]
stack[-1][1] += 1
if k in contexts:
h = contexts[k].headline(n)
if h is None:
l = contexts[k].line(n)
if l is None:
stack.pop()
else:
print l
else:
print '[',h,']'
stack.append([h, 1])
else:
print 'warning : not found ', k
------------
期待通りに、本文中から見出し引用指示を見つけることができました。
stackを追加して、階層構造に対応しました。
stackの中身は、[見出し,行番号]です。
最初に、プログラムの引数である大元のroot.txtの[見出し,1]を積みます。
これで、root.txtの構造に沿って処理が進められます。
本文を一行読んで、行番号を進めます。
本文が空になったら、スタックからその[見出し,*]を降ろします。
本文の一行が見出し指示なら、[見出し,1]を積みます。
スタックが空になったら終了です。
次回でプログラムが完成します。
新規登録で充実の読書を
- マイページ
- 読書の状況から作品を自動で分類して簡単に管理できる
- 小説の未読話数がひと目でわかり前回の続きから読める
- フォローしたユーザーの活動を追える
- 通知
- 小説の更新や作者の新作の情報を受け取れる
- 閲覧履歴
- 以前読んだ小説が一覧で見つけやすい
アカウントをお持ちの方はログイン
ビューワー設定
文字サイズ
背景色
フォント
組み方向
機能をオンにすると、画面の下部をタップする度に自動的にスクロールして読み進められます。
応援すると応援コメントも書けます