ちょっと説明しにくいのですが・・・

 
次のような内容の入ったテキストファイルがあるとします。(生物の類縁関係を表すものです)

(1:0,2:0.001336,((((3:0.002674,4:0,25:0,26:0,50:0):0.001334,5:0.005347,・・・
 
1:とか2:とか3:とかいう部分は生物名のラベルを意味しています。
 
別のテキストファイルにはタブ区切りで、
1 Kainan
2 Gobo
3 Kusimoto
・・・
というように、ラベル名の情報が入っています。
  
最初のファイルの1:とか2:とか3:とかの部分を、Kainan:、Gobo:、Kusimoto: とかいうふうに置き換えたいのです。

以前は手作業でやっていたのですが、あまりに不毛な作業なのでプログラムしたいと考えるようになりました。

参考になるサイトを教えていただければ幸いです。
テキストエディタは秀丸を使っています。
言語はc++をちょっとかじったくらいです。
もちろん、すぐ使えるようなマクロなどあれば大歓迎です。

皆様のお知恵を拝借したいと思います。
よろしくお願いします。



回答の条件
  • URL必須
  • 1人2回まで
  • 登録:2009/11/24 00:57:56
  • 終了:2009/11/24 13:41:56

ベストアンサー

id:neuromancer_sho No.3

neuromancer_sho回答回数28ベストアンサー獲得回数32009/11/24 05:00:47

ポイント50pt

http://dummy/

1つのフォルダに

・目的のファイル(複数可能 名前なんでも).txt

・ラベル名の情報のファイル "label.txt"

・以下を".vbs"をつけて保存したもの

を置いて、vbsファイルをダブルクリックすると、後ろに"_out.txt"のついたファイルが出来上がります。

set fso=createobject("scripting.filesystemobject")
set she=createobject("wscript.shell")
set labels=createobject("scripting.dictionary")
set regex=new regexp
regex.global=true

set_label "label.txt"

for each f in fso.getfolder(".").files
	if f.name<>"label.txt" and right(f.name,4)=".txt" then
		exec f.name
	end if
next

sub set_label(fname)
	set infile=fso.opentextfile(fname)
	regex.pattern="(.*)\t(.*)"
	do while not infile.atendofstream
		line=infile.readline
		set pair=regex.execute(line)(0)
		labels.add pair.submatches(0), pair.submatches(1)
	loop
end sub

sub exec(fname)
	set infile=fso.opentextfile(fname)
	set outfile=fso.createtextfile(fname & "_out.txt")
	regex.pattern="([0-9]+):"
	do while not infile.atendofstream
		line=infile.readline
		for each hit in regex.execute(line)
			hit=hit.submatches(0)
			line=replace(line, hit & ":", labels(hit) & ":")
		next
		outfile.writeline line
	loop
end sub
id:spidermite

プログラムまで組んでいただいてありがとうございました!

出力にびっくりしました。

スクリプト言語は強力なんですね。

興味がわいてきました。勉強してみようと思います。

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

ついでに質問をよろしいでしょうか。(自分でも考えてみます)

上のプログラムだと、二桁の番号がある場合に(ラベルは全部で65番まであります。これは説明すべきでした。すみませんでした)

例えば51: → 5Kushimoto:

となってしまうようです。

これを改良するのはどの部分を変えればよろしいでしょうか。

2009/11/24 13:41:08

その他の回答(2件)

id:haraguci No.1

haraguci回答回数19ベストアンサー獲得回数12009/11/24 01:16:43

ポイント25pt

秀丸ということは Windows ですね。

私としてはこの手の処理には Perl をお勧めします。

Windows なら ActivePerl でしょうか。

http://www.activestate.com/activeperl/

まずはラベル名の入ったテキストファイルを読み込んでハッシュを作り、

次に、類縁関係の入ったテキストファイルをオープンして置換すればいいと思います。

この例だけでは類縁関係のデータフォーマットがよくわかりませんが、

基本的な考え方はこれでいいと思います。

Perl はネット上に情報が多く習得しやすい上に、簡単な処理をさっと書くにもうってつけです。

データ処理が多い仕事だと、今後必ず役に立つと思うので、習得して損はないのではないでしょうか。

id:spidermite

perlについては大学の先生にもおすすめされました。

一度挫折したのですが(インストールで(笑))、修得してみようと思います。

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

2009/11/24 12:54:59
id:t-wata No.2

t-wata回答回数82ベストアンサー獲得回数132009/11/24 02:58:11

ポイント25pt

やりたいことがあまり一般的ではないので、すぐに使えるものは無いと思いますよ。自分で作ったほうが手っ取り早いです。


やり方として考えられるのはる入力テキストを読み込み、別途ラベルファイルも読み込み、ラベルをつけて出力する方法ですかね。

この実現方法としては、本格的にプログラムを組むこともできますが、cygwin+シェルスクリプトなんかで作ったほうが楽だと思います。


シェルスクリプトでやるなら、実装としては、

入力ファイルを読み込んで、変数dataに入れる

ラベルファイルを読み込む

ラベルファイルを1行取り出すごとに、dataを/(,\()$num:/\1$val:/g の正規表現で置換、以下ラベルファイルの末尾まで繰り返す

最後にdataを出力する


という感じですかね。$numはラベルファイルのタブの左側の値、$valはラベルファイルのタブの右側の値を入れた変数です。


cygwinの使い方は以下で。

http://sohda.net/cygwin/

cygwin以外なら、pythonやrubyを使ってもいいです。大体似たようなロジックでいけますが、

その場合は正規表現ではなく構文解析して置換した方がわかりやすいプログラムになると思います。

C++はこの手の作業には面倒なので、スクリプトやスクリプト言語なんかを使ったほうがいいでしょう。

id:spidermite

cygwinというのは聞いたことがありませんでした。勉強してみます。

ありがとうございました

2009/11/24 12:59:53
id:neuromancer_sho No.3

neuromancer_sho回答回数28ベストアンサー獲得回数32009/11/24 05:00:47ここでベストアンサー

ポイント50pt

http://dummy/

1つのフォルダに

・目的のファイル(複数可能 名前なんでも).txt

・ラベル名の情報のファイル "label.txt"

・以下を".vbs"をつけて保存したもの

を置いて、vbsファイルをダブルクリックすると、後ろに"_out.txt"のついたファイルが出来上がります。

set fso=createobject("scripting.filesystemobject")
set she=createobject("wscript.shell")
set labels=createobject("scripting.dictionary")
set regex=new regexp
regex.global=true

set_label "label.txt"

for each f in fso.getfolder(".").files
	if f.name<>"label.txt" and right(f.name,4)=".txt" then
		exec f.name
	end if
next

sub set_label(fname)
	set infile=fso.opentextfile(fname)
	regex.pattern="(.*)\t(.*)"
	do while not infile.atendofstream
		line=infile.readline
		set pair=regex.execute(line)(0)
		labels.add pair.submatches(0), pair.submatches(1)
	loop
end sub

sub exec(fname)
	set infile=fso.opentextfile(fname)
	set outfile=fso.createtextfile(fname & "_out.txt")
	regex.pattern="([0-9]+):"
	do while not infile.atendofstream
		line=infile.readline
		for each hit in regex.execute(line)
			hit=hit.submatches(0)
			line=replace(line, hit & ":", labels(hit) & ":")
		next
		outfile.writeline line
	loop
end sub
id:spidermite

プログラムまで組んでいただいてありがとうございました!

出力にびっくりしました。

スクリプト言語は強力なんですね。

興味がわいてきました。勉強してみようと思います。

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

ついでに質問をよろしいでしょうか。(自分でも考えてみます)

上のプログラムだと、二桁の番号がある場合に(ラベルは全部で65番まであります。これは説明すべきでした。すみませんでした)

例えば51: → 5Kushimoto:

となってしまうようです。

これを改良するのはどの部分を変えればよろしいでしょうか。

2009/11/24 13:41:08
  • id:t-wata
    neuromancer_shoさんのスクリプトの修正ですが、

    line=replace(line, hit & ":", labels(hit) & ":")

    の行を

    line=replace(line, "(" & hit & ":", "(" & labels(hit) & ":")
    line=replace(line, "," & hit & ":", "," & labels(hit) & ":")

    にすると期待通りになりますよ。ちょっと不恰好ですが。
  • id:neuromancer_sho
    あわわ。失礼しました。
    "label.txt"が昇順の場合、sub exec以降を以下の様にすれば解決だと思います。降順であれば回答3のとおりです。
    これを勉強するなら、"vbscript wsh"で検索すると良いと思います。

    sub exec(fname)
    set infile=fso.opentextfile(fname)
    set outfile=fso.createtextfile(fname & "_out.txt")
    all=infile.readall
    for each l_number in reverse_labels
    all=replace(all, l_number & ":", labels(l_number) & ":")
    next
    outfile.write all
    end sub

    function reverse_labels()
    for each l in labels.keys
    rl="," & l & rl
    next
    reverse_labels=split(mid(rl,2), ",")
    end function

  • id:spidermite
    おお、おおお、感動しました。ありがとうございました
    shoさんをはじめ、回答をよせていただいた方に感謝いたします!
    自分でも勉強してみようという気になりました!

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません