テキストファイルについて

ワードやエクセルをいじっていてテキストファイルというと、 なんかしょぼい情報量の少ないファイルであるかのように錯覚してしまいますが、 冷静に考えるとそんなものではないことは、明白です。
テキストと一口に言ってもいろいろです。Postscriptやpdfもある意味テキストですし、SVGもそうです。
画像であってそれがテキストなんて、変な話ですが、バイナリ以外全部と言うことにすると、範囲はとても広いものとなります。
Perlが活躍しているのもこういう背景があるんだと思います。
ここで扱うのは、そんなに広いものではありません。

プレーンテキスト

電子メールや掲示板の発達に伴って誰でも見れるファイルとして、重要性は高まっていると思います。
考えておきたいことは、マックのスタイル付きテキストと言うやつとアスキーアートに関してです。
とりあえず考えるだけでプレーンテキストは何の加工もしないことにします。

スタイル付きテキスト

私は、リソースについて余り詳しくないので、これをうまく活用できてません。
これをリッチテキストとか、htmlとかに変換することは、スキルのある人にとって余り難しいことではないんでしょうけど perlscriptでいろいろ相互に変換できたら楽しいだろうなと思います。 ハイパーカードのフィールドは、フォントが変えられたりかなりいろいろな表現が可能なわけで、それらをうまく活用する とさらに素晴らしくなるとは思います。

アスキーアート

最初はくだらない技術だと思ってましたが、普通のエディタで絵が見れるというのは画期的なことかもしれないと 考えを改めました。
特に表組が興味深いです。
CPANにもアスキーアートの表組をするモジュールや、図を書くモジュールがありました。

use Text::ASCIITable;
$t = new Text::ASCIITable;
$t->setCols(['num','Name','Pos']);
$t->addRow('1','藤本','ショート');
$t->addRow('2','赤星','センター');
$t->addRow('3','今岡','セカンド');
$t->addRow('4','金本','レフト');
$t->addRow('5','檜山','ライト');
$t->alignCol('num','right');
$t->alignCol('Name','center');
$t->setOptions('alignHeadRow','center');
$t->setColWidth('Name',30,1);
print $t->draw( ['+','+','-','+'],
           ['|','|','|'],       
           ['+','+','-','+'],   
           ['|','|','|'],         
           ["+","+",'-','+']   
          );





+-------------------------------------------------+
| num |              Name              |    Pos   |
+-----+--------------------------------+----------+
|   1 |              藤本              | ショート |
|   2 |              赤星              | センター |
|   3 |              今岡              | セカンド |
|   4 |              金本              | レフト   |
|   5 |              檜山              | ライト   |
+-----+--------------------------------+----------+


	
自分でもhtmlのテーブルをアスキーアートで書きだすスクリプトをかいてみましたが、表組というのは、本当に難しいものです。
とくにLatexのようにページの大きさが決まっている中に表を入れるというのは、htmlのようにスクロールで対応できるわけではないので、 とても難しいと思います。
アスキーアートの表からhtmlやLatexの表に変換する、plain2と言うのがあるのを本で見ましたが、自分の環境では、動かなそうです。
ハイパーカードで表組する場合は、あんまり難しい形にしないほうがいいんだとは思いますが、アスキーアートの表は どこでも使えるので、覚えておいて損はないと思われます。
ハイパーカードのフィールドに入れると改行の関係で崩れる可能性があると思います。
ハイパーカードのフィールドは横スクロールがないみたいですし。

マークアップ言語

html

とにかくインターネット上でいちばん多いのがこの形なので、これのビューワを作る事が一番大切です。
htmlのもっとも重要な特徴はハイパーリンクの仕組みだと思います。
HTML::TreeBuilderはかなり強力なので、テキストだけを抜き出すとかいうようなことは簡単にやってくれます。
問題は、ハイパーリンクをどう表現するかとか、表組をどうするかとか、容量の大きいファイルだったらとかいうようなことだと思います。
テーブルレイアウトで作られているものをブラウザ以外でうまくいかすのはとても難しいことです。

簡単なhtmlビューワ

今までの知識を元に簡単なhtmlビューワを作ります。
ローカルのファイルを見るやつを作ります。
とりあえずハイパーカードだけで作ったビューワを改良します。
リンクを入れるフィールドとperlのスクリプトを入れるフィールドを作ります。
この二つのフィールドとテキストの内容のフィールドを重ねることにして、 これをポップアップのボタンで切り替えることにします。
これにhtmlのタイトルタグの部分を入れるフィールドも作ります。
自分のページを読んだ図

perlのスクリプトですが、

#!/usr/local/bin/perl-w
use strict;
use HTML::TreeBuilder;
use HTML::Element;
use Jcode;

my @del = qw(script style form) ;#--このタグが来たらこのツリーごと削除する

open(IN,$ARGV[0]);
my $content = join"",<IN>;
close(IN);

$content = jcode($content)->euc;#--eucにする
$content =~ s/\x0D\x0A|\x0D|\x0A/\n/g;#--改行をそろえる
make_tree($content);

sub make_tree {
	my $content = shift;
	my $tree = HTML::TreeBuilder->new;
	$tree->parse($content);
	
	&edit_tree($tree);
	my $option = {};#無名のハッシュへのリファレンス。いろんな情報を入れる
	&walk_tree($tree,$option);
	$tree->delete;
	
	my@output1=();#--(1)
	my@output2=();
	
	for (my $i= 0;$i< scalar@{$option->{text}};$i += 2)
	{
		my($elm1,$elm2)=($option->{text}[$i],$option->{text}[($i+1)]);
		unless($elm1 eq "" and $elm2 eq ""){
			$elm1= join "\t",reverse split /\t/,$elm1;
			push@output1,"$elm2\t$elm1" if $elm1 ne "";
			push@output2,$elm2;
			}
		}
	
	my $output1 = join "\n", map {jcode($_)->sjis} @output1;
	my $output2 = join "", map {jcode($_)->sjis} @output2;
	my $title = jcode($option->{title})->sjis;
	print $title ,"\r","$output1\r$output2";#LFの区切りでデータを返す。マックでは使わないし。
	}


sub edit_tree {#--ツリーを加工しやすくする。
	my($node)=@_;
	if(ref $node){
		my $tag = $node->tag();
		$node->delete if 1 == scalar grep {$_ eq $tag} @del;#--ツリーごと削除する
		&edit_tree($_) for $node->content_list();
		}
	}

sub walk_tree {#--(2)
	my($node,$option) = @_;
	if(ref $node){
		my$tag=$node->tag();
		if ($tag eq "title" ){$option->{title} = $node->as_text;}
		elsif ($tag eq "br" or  $tag eq "hr"){
			if ($option->{text}[-1] ne "")
			{
				$option->{text}[-1] .= "\n";
				++($option->{char}) ;
				}
			}
		elsif ($tag eq "ul" or $tag eq "ol"){
			push @{$option->{text}},("","\n");
			++($option->{char}) ;
			&walk_tree($_,$option) for $node->content_list();
			$option->{text}[-1] .= "\n";
			++($option->{char}) ;
			}
		elsif ($tag eq "li" ){
			push @{$option->{text}},("","*");
			++($option->{char});
			&walk_tree($_,$option) for $node->content_list();
			$option->{text}[-1] .= "\n";
			++($option->{char}) ;
			}
			#リンクは、絶対指定のものしか拾わない
		elsif ($tag eq "a" and $node->attr("href") and $node->attr("href") =~/^http|^www/){
			if ($option->{text}[-1] eq "")
			{
				$option->{text}[-1].=" ";
				++($option->{char});
				}
			
			push @{$option->{text}},("char ".(($option->{char})+1)." to ","");
			my $str= $node->as_text;
			$option->{char} += length_euc($str);
			$option->{text}[-1] .=  $str;
			$option->{text}[-2] .= ($option->{char})." of card field 2\t".($node->attr("href"));
			push @{$option->{text}},("","");
			}
		else{
			push @{$option->{text}},("","");
			&walk_tree($_,$option) for $node->content_list();
			}
		}
	else{
		$option->{char} += length_euc($node);
		$option->{text}[-1] .=  $node;
		}
	}

sub length_euc { #ハイパーカードの文字の数え方に合わせる
	my ($str) = @_; 
	my ($len,$zen_len) = (length($str),($str =~ tr/\xa1-\xfe//)/2); 
	return  int $len - $zen_len; #intがあるのはうまくいってないから
	}
ほとんど見栄えをよくするために長くなっているんですが、無名のハッシュへのリファレンスまでは普通に 分かるとして、無名のハッシュに入れるものは、タイトルと数えている文字数とテキストです。
テキストは配列になっていて、全体から見るとハッシュの配列という形になってます。
この配列は二個づつ足していかれることになっていて、aタグ以外の時は1番目は空で、2番目にはテキストが入ります。
aタグの時には、char 3 to 8 of card field 2(タブ)(URL) というようなデータが入ります。
これによってグループのテキストスタイルをハイパーカードの方でつけるということになります。
(2)の再帰ループでこれらの情報を集めます。
Perl のリファレンスは、実用Perlプログラミングの最初に詳しく載ってます。
またperldsc.pod、perlref.pod、perllol.podなどにも解説がでていて、これをhtml化して翻訳して下さっているのが、 MacJPerlに入ってました。
$option->{title}がタイトル、$option->{char}が文字数、@{$option->{text}}がテキストの配列です。
(1)からprintまでは、ハイパーカードが、処理しやすいようにデータの形を変えてるだけです。
@output1と@output2はそれぞれテキストの内容のフィールドと、リンクのフィールドに入るデータになります。
つぎは上のPerlscriptを呼び出すファイルリストのフィールドのほうです。

on mouseUp
	do script "set cursor to busy"
	--選んだファイルのパスを得る
	do script "return the selectedText of me"
	set |ファイルの名前| to return value
	if it is "" then return
	do script "the value of word 2 of the long name of this stack"
	set |フォルダ| to return value
	set text item delimiters of AppleScript to {":"}
	set |フォルダ| to (every text item of |フォルダ|)
	set item -1 of |フォルダ| to ""
	set |フォルダ| to |フォルダ| as string
	set |ファイルパス| to |フォルダ| & |ファイルの名前|--(1)
	
	--MacPerlにファイルパスを渡す
	set Perl_script to card field "htmlの解釈"
	
	tell application "MacPerl"
		set |テキスト| to Do Script {Perl_script, |ファイルパス|} mode Batch
	end tell
	
	set text item delimiters of AppleScript to {"
"}--(2)
	--戻り値をフィールドにセットする
	set |テキスト| to every text item of |テキスト|
	set card field "タイトル" to item 1 of |テキスト|
	set card field "リンク" to item 2 of |テキスト|
	set card field "テキストの内容" to item 3 of |テキスト|
	
	--ハイパーリンクをつくる準備
	set |リンクのリスト| to item 2 of |テキスト|
	set text item delimiters of AppleScript to {return}
	set |リンクのリスト| to every text item of |リンクのリスト|--(3)
	set text item delimiters of AppleScript to {tab}
	
	if item 1 of |リンクのリスト| is not "" then --リンクがない場合もある
		set |チャンクリスト| to {}
		repeat with i from 1 to length of |リンクのリスト|
			set |リンク| to item i of |リンクのリスト|
			set |リンク| to every text item of |リンク|--(4)
			set |チャンク| to item 3 of |リンク|
			set end of |チャンクリスト| to |チャンク|
		end repeat
		
		set |リストの長さ| to length of |チャンクリスト|
		
		--リンクが多いと時間がかかるのでやめるかどうか
		if |リストの長さ| > 100 then
			display dialog |リストの長さ| & "個もリンクがあります" & return & ツ
				"時間かかりそうです" buttons {"続ける", "やめる"}
			
			set |結果| to button returned of result
			if |結果| = "やめる" then return
		end if
		
		--リンクのスタイルを作る
		repeat with i from 1 to |リストの長さ|--(5)
			set HT to "set textStyle of " & item i of |チャンクリスト| & "to group"
			do script HT
		end repeat
	end if
	
	
	do script "set the scroll of cd fld \"テキストの内容\" to 0"
	set text item delimiters of AppleScript to {""}
end mouseUp
(1)までで選択されたファイルのパスを得てます。
(2)perlから戻ってきたデータをLFの区切りでリストにして、各フィールドにデータを入れてます。
(3)次にリンクの部分をCRの区切りでリストにして、リンクのリストを作ります。
(4)次にリンクのリストのおのおのをタブの区切りでわけてリンクをつける場所char 3 to 8 of card field 2と いうような参照を得ます。
(5)のループでスタイルをつけます。リンクが多いとかなり時間がかかります。
ほかはちょっと改造しただけです。

これで完成です。
作ったやつを置いておきます。
ダウンロード
容量が大きいと読めないという問題は相変わらずですがhtmlを解釈してくれるというのと 文字コードと改行コードも何とかしてくれるものは出来たわけです。
後はこれをベースにちょっとずつ改良をしていけば、専用ビューワが出来ると思います。
これを改良した例を以下で書きます。