人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

テキストファイルをHTMLファイルにするプログラムを教えてください。
(Perl/Ruby/Pythonのいずれかで)

手元にあるテキストファイルを指定の行数(もしくは文字数)で分割しHTMLファイルにしたいと考えています。
[sample.txt(10分割)→1.html?10.html]

フリーの分割ソフトはあるようですが
・分割とHTML化を同時にしたい
・ページ下部にファイルに対応したページ番号がつけたい
(1.htmlの下部に:<p>1ページ</p>のようなイメージ)
・最近プログラミングの勉強をしていていろんなコードを見てみたい
という理由で利用しないつもりです。

何卒よろしくお願いいたします。

●質問者: kawamori-takumi
●カテゴリ:コンピュータ インターネット
✍キーワード:HTML Perl Python Ruby txt
○ 状態 :終了
└ 回答数 : 4/4件

▽最新の回答へ

1 ● しおり
●23ポイント

こんなのでどうでしょうか。


textplaintohtml.rb:

#!ruby -Ks

require 'jcode'


def put_usage
 $stderr.puts("Usage: #{$0} [-Lnum|-Cnum] file")
end

class TextPlainToHTML
 def initialize(file, template)
 @file = file
 @template = template
 end

 def convert
 no = 1
 foreach(@file) do |part|
 File.open("#{no}.html", "w") do |out|
 html = @template.sub(/>>text<</, part)
 html.gsub!(/>>page_no<</, no.to_s)
 out.write(html)
 end
 no += 1
 end
 end
end

class TextPlainToHTMLDivideByLine < TextPlainToHTML
 def initialize(file, template, num = 10)
 super(file, template)
 @num = num
 end

 protected
 def foreach(file)
 lines = ''
 no = 0
 File.foreach(file) do |line|
 lines << line
 no += 1
 next if no < @num
 yield(lines)
 lines.replace('')
 no = 0
 end
 yield(lines) unless lines.empty?
 end
end

class TextPlainToHTMLDivideByChar < TextPlainToHTML
 def initialize(file, template, num = 100)
 super(file, template)
 @num = num
 end

 protected
 def foreach(file)
 chars = ''
 no = 0
 File.foreach(file) do |line|
 line.each_char do |char|
 next if char == "\n" && chars.empty?
 chars << char
 next if char == "\n"
 no += 1
 next if no < @num
 yield(chars)
 chars.replace('')
 no = 0
 end
 end
 yield(chars) unless chars.empty?
 end
end

template = <<'END_OF_TEMPLATE'
<html>
<body>
>>text<<
<p>>>page_no<<ページ</p>
</body>
</html>
END_OF_TEMPLATE


case ARGV.size
when 1
 type = TextPlainToHTMLDivideByLine
 num = 10
 file = ARGV[0]
when 2
 unless /\A-([LC])(\d+)\z/ =~ ARGV[0]
 put_usage
 exit 1
 end
 type = ($1 == 'L' ?
 TextPlainToHTMLDivideByLine : TextPlainToHTMLDivideByChar)
 num = $2.to_i
 file = ARGV[1]
else
 put_usage
 exit 1
end

converter = type.new(file, template, num)
converter.convert

# まだ「&」が「&amp;」になるバグが直ってない……


使用例:

% ruby textplaintohtml.rb sample.txt
% ruby textplaintohtml.rb -L10 sample.txt
% ruby textplaintohtml.rb -C100 sample.txt
◎質問者からの返答

素晴らしい!

一度はバグが出ましたが該当部分を削除する暫定処置でちゃんと動きました。

このコードを元にいろいろ勉強させていただきます。

(使用例の3番目はうまく行きませんでした。。。)

他の方のコードも引き続き受付けます。


2 ● Alexandre
●23ポイント

hoge.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from optparse import OptionParser
from string import Template
import sys, codecs, os

default_encoding = 'Shift_JIS'
template = u'''\
<html>
<meta http-equiv="content-type" content="text/html; charset=$encoding">
<body>
$text
<p>${page_no}ページ</p>
</body>
</html>
'''

def split_lines(file, lines, encoding):
 text = ''
 no = 0
 try:
 for line in codecs.open(file, 'r', encoding):
 line = line.rstrip(u'\r\n')
 text = ''.join((text, line))
 no += 1
 if lines <= no:
 yield(text)
 no = 0
 text = ''
 if text: yield(text)
 except UnicodeDecodeError:
 sys.exit('input encoding error')
 except LookupError:
 sys.exit('unknown input encoding')

def split_chars(file, chars, encoding):
 text = ''
 try:
 for line in codecs.open(file, 'r', encoding):
 line = line.rstrip(u'\r\n')
 text += line
 while len(text) >= chars:
 yield(text[:chars])
 text = text[chars:]
 if text: yield(text)
 except UnicodeDecodeError:
 sys.exit('input encoding error')
 except LookupError:
 sys.exit('unknown input encoding')

def output_html(text, page, encoding):
 s = Template(template)
 html = s.safe_substitute(encoding = encoding, text = text, page_no=page)
 try:
 f = codecs.open(''.join((str(page),'.html')), 'w', encoding)
 f.write(html)
 finally:
 f.close()

def main():
 parser = OptionParser(usage = '%prog [option] file')
 parser.add_option('-l', type = 'int', dest = 'lines', default = 25)
 parser.add_option('-c', type = 'int', dest = 'chars')
 parser.add_option('-i', '--input-encoding', dest = 'input_encoding', default = default_encoding) 
 parser.add_option('-o', '--output-encoding', dest = 'output_encoding')

 (options, args) = parser.parse_args()
 if len(args) == 0:
 parser.error('No file specified')
 elif not os.path.isfile(args[0]):
 parser.error('No such file')
 if options.chars:
 get_text = split_chars(args[0], options.chars, options.input_encoding)
 else:
 get_text = split_lines(args[0], options.lines, options.input_encoding)
 output_encoding = options.output_encoding
 if not output_encoding:
 output_encoding = options.input_encoding
 for page, text in enumerate(get_text):
 output_html(text, page+1, output_encoding)
 
if __name__ == '__main__':
 main()

使い方

python hoge.py sample.txt
python hoge.py -l 25 sample.txt
python hoge.py -c 400 sample.txt
◎質問者からの返答

今度はPythonですね。

さっそく実行してみます。

ありがとうございました。


3 ● TransFreeBSD
●22ポイント

perlがないので。


使い方

perl hoge.pl -c 3000 sample1.txt sample2.txt
perl hoge.pl -l 20 < sample.txt

オプション c はバイト数、l は行数を引数に取ります。その他の引数を入力ファイルとして、すべてつなげた上で内容を切り分けます。入力ファイルがなければ標準入力を使用します。

若干富豪的です。文字コードは考慮していません。文字数指定時は文字数ではなくバイト数で、指定バイトを超えない行末で切ります。1行が指定バイトを超える場合は、その行は無視します。

◎質問者からの返答

Perlありがとうございます。

これでLL揃いぶみですね!

っと、プログラムが見当たらないので再貼り付けいただければ幸いです。


4 ● lunlumo
●22ポイント

TransFreeBSDさんの例はperlらしくて良いと思いますが,敢えて余りperlらしくないコードを挙げてみます。

#! /usr/bin/perl

packageObject;

usestrict;
useClass::Accessor;
usebase('Class::Accessor');

sub new {
my($pkg) = @_;
my$self;
$self = bless({},$pkg);
$self;
}

packageConfiguration;

usestrict;
useGetopt::Std;
usebase('Object');

__PACKAGE__->mk_accessors(qw(inCode outCode outFile type length inFile template));

sub new {
my($pkg) = @_;
my$self;
$self = $pkg->SUPER::new();
$self->inCode('shiftjis');
$self->outCode('shiftjis');
$self->outFile('output');
$self->type('line');
$self->length(30);
$self;
}

sub initialize {
my($self) = @_;
my$opts = {};
getopts('i:o:f:t:l:',$opts);
$self->inCode($opts->{'i'}) if (defined($opts->{'i'}));
$self->outCode($opts->{'o'}) if (defined($opts->{'o'}));
$self->outFile($opts->{'f'}) if (defined($opts->{'f'}));
$self->type($opts->{'t'}) if (defined($opts->{'t'}));
$self->length($opts->{'l'}) if (defined($opts->{'l'}));
if (scalar(@ARGV) == 2) {
$self->template($ARGV[0]);
$self->inFile($ARGV[1]);
} else {
print "usage: $0 [-i IN_CHARSET] [-o OUT_CHARSET] [-f OUT_FILE_PREFIX] [-t SPLIT_TYPE] [-l SPLIT_LENGTH] TEMPLATE_FILE OUTPUT_FILE\r\n";
print "\tIN_CHARSET:\t(shiftjis|eucjp|utf8)\r\n";
print "\tOUT_CHARSET:\t(shiftjis|eucjp|utf8)\r\n";
print "\tSPLIT_TYPE:\t(line|byte)\r\n";
exit;
}
$self;
}

packageSplitterFactory;

usestrict;

sub getInstance {
my($pkg,$configuration) = @_;
my$instance;
if ($configuration->type() eq 'byte') {
$instance = new ByteSplitter();
} else {
$instance = new LineSplitter();
}
$instance->configuration($configuration);
$instance;
}

packageSplitter;

usestrict;
useEncode;
usebase('Object');

__PACKAGE__->mk_accessors(qw(configuration content));

sub load {
my($self) = @_;
my$configuration = $self->configuration();
my$content = '';
my$in;
open($in,"<:encoding(".$configuration->inCode().")",$configuration->inFile()) || die "";
$content .= <$in> while (!eof($in));
close($in);
$content =~ s/(\r\n|\r|\n)/\r\n/g;
$self->content($content);
$self;
}

sub split {
die "";
}

packageLineSplitter;

usestrict;
usebase('Splitter');

sub split {
my($self) = @_;
my@contents = split(/(?:\r\n|\r|\n)/,$self->content());
my$line = $self->configuration()->length();
my@splitted = ();
while (scalar(@contents)>0) {
my@temp = splice(@contents,0,$line);
push(@splitted,join("\r\n",@temp));
}
@splitted;
}

packageByteSplitter;

usestrict;
useutf8;
useLingua::JA::Fold qw(fold length_half);
usebase('Splitter');

sub cutter {
my($pkg,$length,$string) = @_;
my$chars;
my$shortage;
if ($length >= length_half($string)) {
$chars = length($string);
} else {
$chars = int($length / 2);
$shortage = $length - length_half(substr($string,0,$chars));
while ($shortage != 0) {
if ($shortage > 0) {
$shortage = $length - length_half(substr($string,0,++$chars));
} else {
$chars--;
$shortage = 0;
}
}
}
(substr($string,0,$chars),substr($string,$chars));
}

sub split {
my($self) = @_;
my$content = $self->content();
my$bytes = $self->configuration()->length();
my$temp;
my@splitted;
while ($content !~ m/^(\r\n|\r|\n)?$/) {
($temp,$content) = __PACKAGE__->cutter($bytes, $content);
push(@splitted,$temp);
}
@splitted;
}

packagemain;

usestrict;
useHTML::Template;

eval {
my$configuration = new Configuration()->initialize();
my$splitter = SplitterFactory->getInstance($configuration);
my$template;
my$outFile = $configuration->outFile();
my$inCode = $configuration->inCode();
my$outCode = $configuration->outCode();
my$t;
my@contents;
my$no = 1;
open ($t,'<:encoding('.$inCode.')',$configuration->template()) || die "";
$template = new HTML::Template(
'filehandle'=>$t,
'filter'=> sub {
my($text) = @_;
$$text =~ s/(\r\n|\r|\n)/\r\n/g;
}
);
close($t);
@contents = $splitter->load()->split();
foreach (@contents) {
my$file;
my@lines = map { {'content'=>$_}; } split(/(?:\r\n|\r|\n)/,$_);
my$param = {'output'=>$outFile,'contents'=>\@lines,'no'=>$no};
if ($no != 1) {
$param->{'prev'} = 1;
$param->{'prev_no'} = $no - 1;
}
if ($no != scalar(@contents)) {
$param->{'next'} = 1;
$param->{'next_no'} = $no + 1;
}
$template->clear_params();
$template->param($param);
open ($file,'>:encoding('.$outCode.')',"${outFile}.${no}.html") || die "";
print $file $template->output();
close($file);
$no++;
}
};
die $@ if ($@);

1;

実行には以下のモジュールが必要です。

http://search.cpan.org/~kasei/Class-Accessor-0.31/lib/Class/Acce...

http://search.cpan.org/dist/HTML-Template/

http://search.cpan.org/~hata/Lingua-JA-Fold-0.07/Fold.pm

テンプレートに適用する部分に関しては余り重要ではないとは思いますが,以下の様なテンプレートを想定しています。

<html>
<head>
<title>page<tmpl_var escape="html" name="no"></title>
</head>
<body>
<tmpl_loop name="contents"><tmpl_var escape="html" name="content"><br />
</tmpl_loop>
<tmpl_if name="prev"><a href="./<tmpl_var escape="html" name="output">.<tmpl_var escape="html" name="prev_no">.html">前へ</a></tmpl_if>
<tmpl_if name="next"><a href="./<tmpl_var escape="html" name="output">.<tmpl_var escape="html" name="next_no">.html">次へ</a></tmpl_if>
</body>
</html>
◎質問者からの返答

ありがとうございます。

同じPerlでも書き方がいろいろあるのがよくわかります。

参考にさせていただきます!

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ