日記

RSS 2.0
My Yahoo!に追加


2006年
7月 8月 9月 10月 11月 12月


古い部屋
実験室
その他の部屋へ

2004年3月6日〜

ホームに戻る


【Ruby練習帳】

青空文庫kwic検索再び

 今月14日に作ってみたHyperEstraierを利用した青空文庫全文検索kwic表示をウェブブラウザで利用出来るようにしてみた(つもりだった)。ファイル名を表示させようとするとどうしても14日に示したような結果になってしまう。日本語のファイル名なのが原因だ。ファイルは5000個もあるので、一つ一つアルファベットのみからなるファイル名に変更するのは不可能だ。少なくとも私にとっては。エスケープされた文字列のようなのだが、元に戻す方法が判らない。文字コードもUTF-8ではないようなので、iconvとunescapeを組み合わせていろいろ試してみたがどうしても駄目。escapeされているならこのまま使ってみようと思って、これを表示させるのではなく、リンクにしてしまった。行末の出現行数値をクリックすると、目的のファイルが別窓で表示されるようにしてみたところ、うまくいった。納得できないけれど、まあいいや。「万難を」を検索してみた結果は以下のとおり。ファイルはShift_JISなので、一回目の表示は文字化けしてしまう(Safariではそうなのだが、FireFoxでは大丈夫だった)。

青空文庫検索結果
ところが、何度か試してみると10回のうち9回くらいが、下のようなエラーが出てしまう。何故?
青空文庫検索エラー例
 ときどきうまく行くのがまた不思議である。エラーログを見てもエラーなんか載っていない。

 リンクをクリックしないと作品名・著者名が判らないなど、不便である。近いうちになんとかしたい。

Fri, 29 Sep 2006 14:18:52 GMT

【Ruby練習帳】

Yahoo! Kwic検索

 Kwicである。Quickではない。Keyword in contextである。
 さて、今日はRubyで。XMLの扱い方がなかなか判らずに苦労した。最初はどうして最初の一件しか表示されないのだろう、どうやったら全件表示するのだろうと悩んだ末に、自分で検索件数を1に指定していた。相変わらず莫迦である。

<%
$>.content_type = 'text/html; charset=UTF-8'
%>

<html>
<head>
  <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <link rel="stylesheet" type="text/css" href="yhkwic.css" />
  <title>Yahoo KWIC</title>
</head>
<body>

<form action="yhkwic.rhtml">
  Keyword:<input name="Keyword"> 
  <input type=submit value="Search">
</form>

<%
require 'cgi'
require 'net/http'
require 'rexml/document'
require 'uri'
cgi = CGI.new

if cgi['Keyword'] == nil
puts "Keyword欄に検索したい語を入力してください。"
elsif
cgi['Keyword'] == ""
puts "Keyword欄に検索したい語を入力してください。"
else
print "<hr />\n<ol>\n"

word = Regexp.new(cgi['Keyword'])

url = URI.escape("http://api.search.yahoo.com/WebSearchService/V1/webSearch?
		appid=yahooappid&query=#{word}&results=50")

begin
   res = Net::HTTP.get_response(URI.parse(url))
   results = REXML::Document.new(res.body)
   results.root.each_element do |result|
     summary = result.elements[2]
     click = result.elements[4]
     line = "                          " + summary.text
     position = line.index(word)
       if position != nil
       print "<li><a href='"
       print click.text
       print "' target='_blank'>#</a> "
       res = line[position-25, 50+word.to_s.length]
       res.grep(word){|kwic|
       print kwic.gsub(word){|s| "<kywd>" + s + 
                "</kywd>"}.gsub(/ /,'&nbsp;')
       }
    print "</li>"
    end
  end
rescue
   print "<br />Connection error."
end
end
%>
</ol>
<hr />
</body>
</html>
 yahooappidの箇所は、自分のYahoo APIのIDを入れる場所なのでそのまま使わないように。結果表示の上限は50件にしています。実際に表示される件数が50よりも少なかったら、Summaryに検索に使った語が含まれていなかったのかも知れません。そのかわりTitleに含まれていたのかも。ときどき、理由は判りませんがエラーが出ることがあります。実際に使えるようにしてみたのが、ここ。#をクリックすると該当ページが別窓で表示されます。検索には欧文のみ使用でいます。日本語を入れても結果には何も表示されないでしょう。ところで、PHP版にも同じ語を入れて検索してみると、検索結果が違うのはなぜだろう。表示順の指定がちがうのだろうか。指定なんかしただろうか。

 検索語をYahoo.comに送って、XML形式で帰ってきた結果のSummaryの部分を検索語を中心に配置されるようにしているだけです。このところずっと作ってきたものとほとんど変わらないので、説明は不要でしょう。

Thu, 28 Sep 2006 12:35:59 GMT

【Ruby練習帳】

Yahoo! 検索

 Yahoo! Developer NetworkのRuby Developer Centerを見て少し試してみたのだが、どうもうまく結果が取得できない。あれこれ試行錯誤して、何とか検索結果を受けとるところまで漕ぎ着けたが、XMLをどう扱ったらいいのか判らないので、今日はそれまで。
 ところで、私のubuntuでは、rhtmlがpublic_htmlの第一層にないと(フォルダの中に入っていると)GETで単語を次のページに送れないのだ。それが五回に一回くらいうまく行くのが不思議なところだ。

【PHP】

Yahoo! 検索
 これを機会にPHP版Yahoo! 検索kwic表示を少しだけ改良してみた。
<?php

$key = $_POST['word'];
$limit = $_POST['limit'];

if ($key==""){
echo "検索語を入れて、<strong>Search</strong>ボタンを押してみてください。
      検索は<a href='http://www.yahoo.com/'>Yahoo!</a>のウェブサービス(API)を利用します。<br />";
}else{

echo "<hr /> 検索語(欧文の場合は右矢印)をクリックすると該当記事が別窓で表示されます。<ol>";

$url="http://api.search.yahoo.com/WebSearchService/V1/webSearch?
		appid=yahooappid&query=".urlencode($key)."&results=".$limit;
$xml = file_get_contents($url);
$xs = simplexml_load_string($xml);


  $len=strlen($key);
  foreach ($xs->Result as $value){
  $summary=$value->Summary;
  $summary="                          ".$summary;
  $result = strpos($summary,$key);
  if ($result == true){
    $sentence=substr($summary,$result-25,$len+58);
    $sentence=preg_replace("/\n/"," ",$sentence);
    $sentence=str_replace($key,"<em>".$key."</em>",$sentence);
    $sentence=str_replace(" ","&nbsp;",$sentence);
    echo "<li><a href='".$value->ClickUrl."' target='_blank'><em>→</em></a>";
    echo $sentence."</li>";
    }
  }
echo "</ol>";
}
?>
一部だけ、抜粋。PHPでできたんだから、いまさらRubyで作らなくてもいいかなという気分になってきている。

Wed, 27 Sep 2006 13:10:47 GMT

【Ruby練習帳】

PubMed検索・その4

 さて、PubMed検索シリーズの最後は単語の集計である。WebLSDでの単語集計は、昨日作った頻度別の並べ替えに近い。今日作るのは、関心のある単語で検索したら、その論文の要旨にはどのような単語がどれくらい使用されているのかを全部数え上げようというものだ。この単語の種類と頻度をさまざまなキーワードで検索した結果を使って解析すると、単語同士の結びつきの組合わせと強さが判るのである。そういうことはいろいろなところで利用されている方法である。
 まずは、最初の検索結果の画面の下に、頻度集計用のリンクを追加するために、この一行を挿入。
print "<td style='background-color:lightgray'rowspan='2'><a href='pmkwic3.rhtml?kwrd=#{cgi.params['Keyword'][0]}' target='_blank'>集計</td>"
 これで下のようなリンク表になる。

PubMed検索結果表

 ここではキーワードを次のページに送るだけ。最初の検索では要旨を全部保存していないので、実は集計用のページを開くともう一回検索をする。しかし、集計値を出す頻度はそんなに高くはないだろうと思っているからだ。よく使う人は自分で考えてみてください。もう一回検索して、次々に要旨の文を全部一つの文字列へと流し込んでいく。次に単語を全部集計して、まず左側で頻度順、右側にアルファベット順でその集計値を示す。
<%
$>.content_type = 'text/html; charset=UTF-8'
%>

<html>
<head>
  <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <link rel="stylesheet" type="text/css" href="pmkwic.css" />
  <title>PubMed KWIC</title>
</head>
<body>

<%
require 'bio'
require 'cgi'
cgi = CGI.new
count = Hash.new(0)

keywords = cgi.params['kwrd'].to_s.gsub(/_/,'-')

options = {
  'mindate' => '1996',
  'maxdate' => '2006',
  'retmax' => 3000,
  }
  
    def ab(str = nil)
      @abstract ||= str
      lines = []
      lines << @abstract
      return lines.join("\n\n")
    end

text = ""
entries = Bio::PubMed.esearch(keywords, options)

Bio::PubMed.efetch(entries).each do |entry|
  biomed = Bio::MEDLINE.new(entry)
  abstract = biomed.ab
  text << abstract + " "
end

words = text.gsub(/\.|,|:|;|\"|\'|\?|\(|\)/,'').split
words.each{|word|
  count[word] += 1
}

print "<div align='center'><table border='0' cellpadding='15'><tr>"
print "<td style='background-color:lightgray'>頻 度 順</td><td 
      style='background-color:lightgray'>アルファベット順</td></tr><tr>"
print "<td style='background-color:beige'><ol>"

count.sort{|a,b|
	a[1] <=> b[1]
}.reverse.each{|key, value|
	print "<li>#{key}: #{value}</li>\n"
}
print "</ol></td><td style='background-color:beige'><ol>"

count.sort.each{|key, value|
	print "<li>#{key}: #{value}</li>\n"
}

print "</ol></td></tr></table></div>"
%>

<hr />
</body>
</html>
 単語集計のときには引用符とかピリオド、コロンなどは消してから数えている。大文字小文字を区別するので文頭で大文字になったものは別に集計されてしまう。気に入らない人は自分で検討して下さい。私は文頭かどうかを知りたいことがあるから、それはこのままにしておきたい。ピリオドを消してしまったので、文末かどうかの識別が困難になった。試してみるとちゃんと数え上げてくれて、以下のような結果が出た。
PubMed検索結果4

 左が頻度順で、よく使われるof、the、andが上に並んでいる。少し下って、genesとか、metagenome、microbial、diversityといったあたりから論文の特徴が見え始める。同じ集計値をアルファベット順で示したものだが、上の方は数字と記号ばかりで面白くない。
 とりあえず、目的通りのものがあっというまに出来てしまったので、少し休むかも知れない。でも、こんなに短時間に作れたのはRubyだからだろうか。

Tue, 26 Sep 2006 13:22:35 GMT

【ubuntu】

OpenOffice.org

 OpenOffice.orgが使えなくなってしまったことが前にもあって、libGL.so.1.2を入れ替えればいいことを思い出し、やってみたらちゃんと動くようになった。

【Ruby練習帳】

PubMed検索・その3

 どうしてelseifが使えないんだろうと思っていたら、Rubyではelsifだったと今日初めて知った。驚いた。elseifでもelse ifでもなく、elsifだとは。

 さて、用例検索を前後の語(すなわち共起する語である)の出現頻度の高い順に並べかえてみよう。最初のページには、

print "<div align='center'><table border='0' cellpadding='15'><tr>"
print "<td stype='background-color:grey'>ABC順</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wb2;ord=abc' target='_blank'>2語前でソート</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wb1;ord=abc' target='_blank'>1語前でソート</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wf1;ord=abc' target='_blank'>1語後でソート</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wf2;ord=abc' target='_blank'>2語後でソート</td>"
print "</tr><tr>"
print "<td stype='background-color:grey'>頻度順</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wb2;ord=frq' target='_blank'>2語前でソート</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wb1;ord=frq' target='_blank'>1語前でソート</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wf1;ord=frq' target='_blank'>1語後でソート</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wf2;ord=frq' target='_blank'>2語後でソート</td>"
print "</tr></table></div>"
というのを加えて、並べ替えの種別と、並べ替えに使う語の位置を次のページに送信するようにする。それを受けたら、アルファベット順か頻度順かで表示方法を変えるようにすればいい。こんな感じに:
<%
$>.content_type = 'text/html; charset=UTF-8'
%>

<html>
  <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <link rel="stylesheet" type="text/css" href="pmkwic.css" />
<body>
<ol>
<%
require 'mysql'
require 'cgi'
cgi = CGI.new

position = cgi.params['pos'].to_s
srtordr = cgi.params['ord'].to_s

my = Mysql::new("host", "userid", "password", "paperdb")

if srtordr == 'abc'
res = my.query("select kw, sentence, #{position}, pmid from pmkwic 
  		order by #{position}")
res.each do |row|
  kwic2 = row[1].gsub(/#{row[0].gsub(/_/," ")}/,"<kywd>#{row[0]
  			.gsub(/_/," ")}</kywd>")
  if /\A\w+\Z/ =~ row[2]
    kwic2 = kwic2.gsub(/#{row[2]}/,"<mrkd>#{row[2]}</mrkd>")
  end
  print "<li>"
  print kwic2.gsub(/ /,' ')
  print " <a href='http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?
  		db=pubmed&cmd=Retrieve&dopt=AbstractPlus&list_uids=" + 
		row[3] + "&' target='_blank'>" + row[3] + "</a>"
  print "</li>\n"
end

elsif srtordr == "frq"
res = my.query("select #{position},count(*) as number from pmkwic 
  		group by #{position} 
			order by number desc")
res.each do |row|
  res2 = my.query("select kw,#{position},sentence,pmid from pmkwic where 
  		#{position} = '#{row[0]}'")
    res2.each do |row2|
    kwic2 = row2[2].gsub(/#{row2[0].gsub(/_/," ")}/,"<kywd>#{row2[0]
			.gsub(/_/," ")}</kywd>")
  if /\A\w+\Z/ =~ row2[1]
    kwic2 = kwic2.gsub(/#{row2[1]}/,"<mrkd>#{row2[1]}</mrkd>")
  end
  print "<li>"
  print kwic2.gsub(/ /,' ')
  print " <a href='http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?
  		db=pubmed&cmd=Retrieve&dopt=AbstractPlus&list_uids=" + 
		row2[3] + "&' target='_blank'>" + row2[3] + "</a>"
  print "</li>\n"
  end
end
end
my.close
print "</ol>"
print "<div align='center'><table border='0' cellpadding='15'><tr>"
print "<td style='background-color:lightgray'>ABC順</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wb2;ord=abc'>2語前でソート</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wb1;ord=abc'>1語前でソート</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wf1;ord=abc'>1語後でソート</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wf2;ord=abc'>2語後でソート</td>"
print "</tr><tr>"
print "<td style='background-color:lightgray'>頻度順</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wb2;ord=frq'>2語前でソート</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wb1;ord=frq'>1語前でソート</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wf1;ord=frq'>1語後でソート</td>"
print "<td style='background-color:beige'><a href='pmkwic2.rhtml?
	pos=wf2;ord=frq'>2語後でソート</td>"
print "</tr></table></div>"

%>
<hr />
</body>
</html>
 検索結果はこんな感じ。size standardという語を検索して、一つ前の語の頻度順に並べたもの。一つ前の語が「a」のときに、ちょっとみっともない着色がなされていることが一目瞭然である。下のリンクを押せば、何度でも好きな並べ替えをしてくれる。
PubMed検索結果例3

 次回は、単語を集計してみる。

Mon, 25 Sep 2006 14:07:06 GMT

【Ruby練習帳】

PubMed検索・その2

 さて、PubMed検索のキーワード検索の結果を、キーワードの前後の単語に従って並べ替えてみよう。今回はMySQLを使うことにするので(使わなくてもできるような気もするが、いろいろな並べ替えには便利なのでこれを使う。PHPでやってみたときの経験からそう判断した)、Ruby/MySQLをインストールする。
 まずMySQLにデータベースとテーブルを作る。テーブルには、最初の検索結果の一行、pmid、検索語(keyword)、検索語の一つ前の単語、二つ前の単語、一つ後の単語、二つ後の単語を収納する場所を用意する。そのテーブルをpmidtableと名付けよう。データベースはpaperdbという名である。もちろん、これらの名前は好き勝手につけて構わない。
my = Mysql::new("localhost", "userid", "password", "paperdb")
init = my.query("delete from pmidtable")
とやって、データベースに接続準備をして、pmidtableを空っぽにする。このテーブルは何度も使い回すのだ。もしも一般公開するなら、そうはいかないだろうが、これは自分専用だからいいのだ。
 昨日と同様に一回目の検索結果を表示すると同時に、文をばらばらにしてテーブルに収納する。こんな感じ:
devided = kwic.gsub(/\"|\'/,"").split(/#{word}/)
bwords = devided[0].gsub(/\.|,|:|;|(|)/,"").strip.split(/ /).reverse
fwords = devided[1].gsub(/\.|,|:|;|(|)/,"").strip.split(/ /)
insrt = my.query("insert into pmidtable (pmid,kw,sentence,wb1,wb2,wf1,wf2) values ('#{pmid}','#{cgi.params['Keyword'][0]}','#{my.quote kwic}','#{bwords[0]}','#{bwords[1]}','#{fwords[0]}','#{fwords[1]}')")
 ここで、kwが検索に使った語、wb1が一つ前、wb2が二つ前、wf1が一つ後、wf2が二つ後の単語である。並べ替えるときに、ピリオドやコンマを含めるかどうかで悩む。残しておいた方が文末で使われるとかいう情報が得られていいのではないかと思ったが、今回はピリオド、コンマ、コロン、セミコロン、括弧を除外することにした(が、括弧は実際には除外されなかった。なぜだろう)。最後に並べ替えの結果を評するページへのリンクを置く。ここでURLに送り込みたい文字列をつけて、次のページで受け取る方法がなかなか判らず時間がかかってしまった。出来上がったのは、以下のようなものである。

<%
$>.content_type = 'text/html; charset=UTF-8'
%>

<html>
  <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <link rel="stylesheet" type="text/css" href="pmkwic.css" />
<body>

<%
require 'mysql' 
require 'bio'
require 'cgi'
cgi = CGI.new
%>

<form action="pmkwic.rhtml">
  Keyword:<input name="Keyword"> 
  <input type=submit value="Search">
</form>

<%
if cgi.params['Keyword'][0] == nil
puts "Keyword欄に検索したい語を入力してください。"
else

print "<hr />\n<ol>"

word = Regexp.new(cgi.params['Keyword'][0].gsub(/_/,' '))
keywords = cgi.params['Keyword'][0].gsub(/_/,'-')

options = {
  'mindate' => '1996',
  'maxdate' => '2006',
  'retmax' => 3000,
  }
  
    def pmid
      return @pubmed
    end
  
    def ab(str = nil)
      @abstract ||= str
      lines = []
      lines << @abstract
      return lines.join("\n\n")
    end

my = Mysql::new("localhost", "userid", "password", "paperdb")
	
init = my.query("delete from pmidtable")

entries = Bio::PubMed.esearch(keywords, options)

Bio::PubMed.efetch(entries).each do |entry|
  biomed = Bio::MEDLINE.new(entry)
  pmid = biomed.pmid
  abstract = "                                           " + biomed.ab
  
  startpos = 0
  while position = abstract.index(word,startpos) do
    if position != nil
      kwic = abstract[position-42, 80+keywords.length]
      result = kwic.gsub(word){|s| "<key>" + s + "</key>"}
      result = result.gsub(/ /,'&nbsp;')
      print "<li>" + result
      print " <a href='http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=pubmed&cmd=Retrieve
	 	 &dopt=AbstractPlus&list_uids=" + pmid + "&' target='_blank'>" + pmid + "</a>"
      print "</li>\n"
	  
	  devided = kwic.gsub(/\"|\'/,"").split(/#{word}/)
	  bwords = devided[0].gsub(/\.|,|:|;|(|)/,"").strip.split(/ /).reverse
	  fwords = devided[1].gsub(/\.|,|:|;|(|)/,"").strip.split(/ /)
      insrt = my.query("insert into pmidtable (pmid,kw,sentence,wb1,wb2,wf1,
		  wf2,sentence_b,sentence_f) values ('#{pmid}','#{cgi.params['Keyword'][0]}',
		  '#{my.quote kwic}','#{bwords[0]}','#{bwords[1]}','#{fwords[0]}','#{fwords[1]}',
		  '#{my.quote devided[0]}','#{my.quote devided[1]}')")
	  
      startpos = position + 1
    end
  end
end
my.close
print "</ol>"
end
%>
<div align="center"><table border="0" cellpadding="15"><tr>
<td style="background-color:beige"><a href="pmkwic2.rhtml?wb2" target="_blank">2語前でソート</td>
<td style="background-color:beige"><a href="pmkwic2.rhtml?wb1" target="_blank">1語前でソート</td>
<td style="background-color:beige"><a href="pmkwic2.rhtml?wf1" target="_blank">1語後でソート</td>
<td style="background-color:beige"><a href="pmkwic2.rhtml?wf2" target="_blank">2語後でソート</td>
</tr></table></div>
<hr />
</body>
</html>
 ちょっと長くなってしまった。さて、pmkwic2.rhtmlというファイルへと情報を送ったら、自分の調べたい位置の語で並べ替えて表示するのは、MySQLがやってくれるので簡単だ。
<%
$>.content_type = 'text/html; charset=UTF-8'
%>

<html>
  <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <link rel="stylesheet" type="text/css" href="pmkwic.css" />
<body>
<ol>
<%
require 'mysql'

srtw = ENV['QUERY_STRING']

my = Mysql::new("localhost", "userid", "password", "paperdb")
res = my.query("select kw, sentence, #{srtw}, pmid from pmidtable order by #{srtw}")
res.each do |row|
  kwic2 = row[1].gsub(/#{row[0].gsub(/_/," ")}/,"<zzz>#{row[0].gsub(/_/," ")}</zzz>")
  if /\A\w+\Z/ =~ row[2]
    kwic2 = kwic2.gsub(/#{row[2]}/,"<qqq>#{row[2]}</qqq>")
  end
  print "<li>"
  print kwic2.gsub(/ /,' ')
  print " <a href='http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?
  		db=pubmed&cmd=Retrieve&dopt=AbstractPlus&list_uids=
  		" + row[3] + "&' target='_blank'>" + row[3] + "</a>"
  print "</li>\n"
end
my.close
%>
</ol>
<div align="center">
<table border="0" cellpadding="15"><tr>
<td style="background-color:beige"><a href="pmkwic2.rhtml?wb2">2語前でソート</td>
<td style="background-color:beige"><a href="pmkwic2.rhtml?wb1">1語前でソート</td>
<td style="background-color:beige"><a href="pmkwic2.rhtml?wf1">1語後でソート</td>
<td style="background-color:beige"><a href="pmkwic2.rhtml?wf2">2語後でソート</td>
</tr></table>
</div>
<hr />
</body>
</html>
 あとは何度でもソートのやり直しができる。ExoIIIという語で検索して、一つ前の語で並べ替えた結果を例として示す(クリックすると大きくなります)。
PubMed検索結果例2

 最後の方だけ示したのは、上の方には括弧やピリオドが前に来るのが並んでいるからだ。一つ前の語を赤くしているのだが、もちろん好みで検索語を赤にしたっていい。前の語がasとかanのように短い文字列だと、他の単語の間のasやanに色がついてしまうのがみっともない。ハイフンが入っていると色がつかなかったりする。

 WebLSDと比べてみると、さまざまな違いに気づく。WebLSDは検索結果数が少ないのに、論文の発表年代は幅広い。PubMedで検索するときには科学的なキーワードでないと検索結果がうまく出てこないが、WebLSDでは一般的な単語でもちゃんと結果が表示される。これは、英語の用例を検索するという目的のためには不可欠な条件である。私の作ったものはその根本的なところで失格である。しかし、それは私のせいではないのではなかろうか。PubMedの検索方式の特徴ではないだろうか。WebLSDは、PubMedのabstractなどの情報を自前のサーバーに保存しているのではないだろうか。各年代からランダムに抽出して。だから、metagenomeという語で検索しても、「該当する表現がありませんでした」という結果が返ってくるのではないだろうか。勝手に保存したらいけないのではないかということを糾弾するつもりはまったくない。なくなったら私も困るし。

 次は、並べ替えをアルファベット順ではなく、頻度順に表示するのにも挑戦してみよう。一番良く使われる言い回しは何かを知りたいことも多いからだ。

Sun, 24 Sep 2006 11:39:46 GMT

【Ruby】

Ruby Developer Center

 Yahoo! Developer NetworkRuby Developer Center発足のお知らせが掲載されていた。Rubyを使ってやりとりする方法が紹介されているようだけど、まだ記事は少ないような気がする。そのうち、少し真面目に検索結果をkwic表示するサイトを作ってみようか。前に試しに作ってみたものがあるけど、あまり出来が良くなくて。

【Ruby練習帳】

PubMed検索:第2回

 さて、昨日作ったもののhtml化を行ないました。キーワードをcgiで送り込むことと、結果表示をhtmlで行なうとともに、該当論文のリンク先を作ることが、追加されたところ。検索オプションとして対象を1996年から2006年の10年に限定してみた。これは、入力画面から設定できるようにした方がいいだろう。スペースはいくらあってもWebブラウザでは1個分にしかならないので、&nbsp;に変換すると同時に、検索語に色を付ける。このところが実は厄介で、タグの中のスペースが変換されてしまうと思うような結果が得られないことになる。そこでちょっと強引だが、<key>というタグを作ってしまい、cssでフォントを指定した。それからフレーズとして検索したい場合は、単語間にアンダーバーを入れることにする。スペースで区切られたものは、AND検索になってしまうから。これをPubMed検索にはハイフンに置き換えて送りだし、kwic表示のためにはスペース置き換えて利用する。そうしないと、本当にハイフンを含む語の検索ができなくなってしまうから。こんな簡単なものでも結構苦労したのだ。一応できあがったのが以下のようなもの(リンクのところは本当は一行で)。

<%
$>.content_type = 'text/html; charset=UTF-8'
%>

<html>
  <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <link rel="stylesheet" type="text/css" href="pmkwic.css" />
<body>

<%
require 'bio'
require 'cgi'
cgi = CGI.new
%>

<form action="pmkwic.rhtml">
  Keyword:<input name="Keyword"> 
  <input type=submit value="Search">
</form>

<%
if cgi['Keyword'][0] == nil
puts "Keyword欄に検索したい語を入力してください。"
else

print "<hr />\n<ol>"

word = Regexp.new(cgi['Keyword'][0].gsub(/_/,' '))
keywords = cgi['Keyword'][0].gsub(/_/,'-')

options = {
  'mindate' => '1996',
  'maxdate' => '2006',
  'retmax' => 3000,
  }
  
    def pmid
      return @pubmed
    end
  
    def ab(str = nil)
      @abstract ||= str
      lines = []
      lines << @abstract
      return lines.join("\n\n")
    end
  
entries = Bio::PubMed.esearch(keywords, options)

Bio::PubMed.efetch(entries).each do |entry|
  biomed = Bio::MEDLINE.new(entry)
  pmid = biomed.pmid
  abstract = "                                           " + biomed.ab
  
  startpos = 0
  while position = abstract.index(word,startpos) do
    if position != nil
      kwic = abstract[position-42, 80+keywords.length]
      result = kwic.gsub(word){|s| "<key>" + s + "</key>"}
      result = result.gsub(/ /,' ')
      print "<li>" + result
      print " <a href='http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=pubmed&cmd=Retrieve&
               dopt=AbstractPlus&list_uids=" + pmid + "&' target='_blank'>"
               + pmid + "</a>"
      print "</li>\n"
      startpos = position + 1
    end
  end
end
print "</ol>"
end
%>
<hr />
</body>
</html>
 これで検索してみたときの結果例を示す。bacterial communityという語句を検索したときのものである。
PubMed検索結果例1

 いやあ、遅い。時間がかかりすぎる。他にもいろいろと問題があることに気づく。WebLSDで同じ語句を入力して結果を比べてみると、あちらはすぐに結果が表示される。数は11件しかないのに比べて、私が作った方は1043件も表示された。こんなに要らないという気はする。他に、小文字で始まる語を入れても、結果には大文字で始まる語も表示される。これは正規表現による検索と表示のところを工夫すればなんとかなりそう。communityで検索して、communitiesが表示されるのは、ちょっと私の手には負えないかもしれない。辞書が必要だからだ。辞書の照合までしていたら、さらに時間がかかってしまい、使い物にならないものになってしまいそう。悔しいが、何年もかけて作り上げてきたものと、一晩で作ったものの違いだということで、自分を納得させることにしよう。さて、明日以降は「2語前でソート」「1語前でソート」「1語後でソート」「2語後でソート」に挑戦してみよう。

【Ruby】

届いた本

 またRuby on Railsの本を買ってしまった。薄いけれども判りやすそうな気もする。しかし、英語だ。

_ Amazon.co.jp
Ruby on Rails: Up And Running
Oreilly (2006/08)
¥ 3,120 (税込)
在庫あり
Sat, 23 Sep 2006 08:13:42 GMT

【Ruby練習帳】

PubMed検索

 WebLSDという素敵なサイトがあって、ここの共起検索が素晴らしい。何年も前から利用している。PubMed検索のキーワード検索の結果として得られた論文の要旨の文章が、kwic検索の結果となって表示される。前後の語で並べ替えたりできるところがいいのだ。ということで、今日からこれを自分で作ってみることにしよう。
 まずはコマンドラインで使うものから始める。前に保存してあるテキストファイルでkwic検索するものをすでに作っているから、BioRubyでPubMedの論文を検索した結果に適用してみる。

#! /usr/bin/ruby

require 'bio'

keywords = ARGV[0]

if ARGV[1] == nil
  word = ARGV[0]
else
  word = Regexp.new(ARGV[1])
end

options = {
  'retmax' => 1000,
  }
  
    def pmid
      return @pubmed
    end
  
    def ab(str = nil)
      @abstract ||= str
      lines = []
      lines << @abstract
      return lines.join("\n\n")
    end
  
entries = Bio::PubMed.esearch(keywords, options)

Bio::PubMed.efetch(entries).each do |entry|
  biomed = Bio::MEDLINE.new(entry)
  pmid = biomed.pmid
  abstract = "                                           " + biomed.ab
  
  startpos = 0
  while position = abstract.index(word,startpos) do
    if position != nil
      kwic = abstract[position-42, 84]
      print kwic.sub(word){|s| " " + s + " "}
      print " "
      p pmid
      startpos = position + 1
    end
  end
end
とまあこんな具合である。いきなりできたように見えるが、何時間もかかっている。BioRubyは使い方の詳しい説明がどこにもないから大変だ。そのうえ、Rubyがまだよく判っていないのだから、なおさらである。このファイルをpubmed.rbとかいう名前で保存し、検索したい語を指定する。今回は、PubMedで検索する語と、Kwic検索の語を別に指定できるようにしてみた。例えば、ruby pubmed.rb exonucleaseIII restrictionとすれば、exonucleaseIIIという語を要旨に書いていた論文の要旨の文の中でrestrictionという言葉がどのように使われているかを調べられるというわけだ。そんなことをしたがる人がいるかどうかは私は知らない。結果は、こんな感じ。
$ ruby pubmed.rb ExonucleaseIII restriction
                           The type I DNA  restriction  and modification systems of en "9799635"
as cloned in E. coli was cleaved with the  restriction  endonucleases Eco RI, Hind III "788917"
ns. Total sea urchin DNA was cleaved with  restriction  endonucleases, fractionated on "788917"
 コマンドラインではやはり寂しい。せっかくpmidを書きだしているのだから、これをクリックしたら、PubMedの該当ページが表示されるようにしたりしたいと思うのが人間というものであろう。
 詳しい説明をしようと思っていたけれども、面倒臭くなったので、もう風呂に入って寝てしまおう。明日はこれをHTMLに組み込む予定。本気ですよ、私は。

Fri, 22 Sep 2006 12:45:43 GMT

【PHP】

載っていた!

 今日届いたPHP Cookbook, 2nd Editionは、760ページに及ぶ大著で、字がびっしり詰まっていて嬉しくなってしまう。もちろん、コマンドラインでの利用についての記述もあり、$argvと$argcについても書いてあった。このCookbookシリーズは一体誰がそんなもの使うんだろうというような利用法も詳しく書いてあって本当に役立つのだ。第1版のときに買っていれば、かなりの時間の節約ができたかも知れないと思う。どうして$argv[0]がプログラム名なんだろうと思っていたのだが、phpという文字に続く文字列はすべてphpというコマンドに続く引数で、その最初のものがプログラム名に相当するという考え方らしい(本当か?)。
 今日は予想外の事件が起きて、いろいろ試せず。

_ Amazon.co.jp
Php Cookbook 2nd Edition
Oreilly (2006/08)
¥ 4,681 (税込み)
通常1~3週間以内に発送
Thu, 21 Sep 2006 14:42:53 GMT

【PHP】

知らなかった!

 PHPでもargvを使えると初めて知った。ほら、コマンドラインで何かさせるときに、コマンドの後ろに検索語とかファイル名とか書いてプログラムに知らせる、あれですよ。$argv[0]がプログラム名で、$argv[1]以降が引数、$argcが引数の数だといふ。全然知らなかった。これまで、結構PHPの本は読んできたのだけど、書いていなかったような気がする。確かにPHPはコマンドラインでの利用は少ないかも知れないが、これくらい教えてくれたっていいではないか。私はコマンドラインでも使うのだ。この頃は、Rubyなんか練習しているけれど、つい数週間前まではPHP一筋だったのだから。Rubyであれこれ試しているときに、どうしてPHPではこうやっていろいろな指示をプログラムに送り込めないのだろうと思っていたのだった。この貴重な情報を偶然見つけたのは、MySQLの本。素晴らしい本である。

_ Amazon.co.jp
MySQLクックブック〈VOLUME1〉
オライリージャパン (2003/11)
¥ 5,670 (税込み)
在庫あり
Wed, 20 Sep 2006 12:36:35 GMT

【Ruby練習帳】

判った!

 ubuntuでだけrhtmlファイルがうまく動かず「ダウンロードしますか」という表示が出てしまう問題の解決法が載っているサイトを見つけた(しかし、そこのURLを記録していなかったので、もう二度と見つけられないのが残念)。解決法は、スクリプトの一番最初に、

<%
$>.content_type = 'text/html; charset=UTF-8'
%>
を追加するというもの。charsetは自分の環境に合わせて。最初の$>.はよく判らない。なぜubuntuでのみ起こる現象なのかも判らないが、解決したらいいことにする。

 さて、rhtmlファイルが動くようになったので、簡単なページを作ってみる。コメントを送って表示するというもの。

<html><head><title>eRuby test</title></head><body>

<form action="test3.rhtml">
    コメント欄:<input name="comment"><br>
    <input type=submit value="送信">
</form>

<%
require 'cgi'
cgi = CGI.new

if cgi['comment'][0] == nil
print "まだ何も入力していませんね。"
else
print "あなたがコメント欄に入力した値は、<strong>『"
print cgi['comment'][0]
print "』</strong>です。<br />"
end
%>

</body>
</html>
 自分のコメントを送って、入力しているときのみその内容を表示しようと思ったわけだ。だから、最初にこのページを開くと、「まだ何も入力していませんね。」と表示される。ところが、何も入れずに送信ボタンを押すと「力した値は、『』です。」と表示されてしまう。そこで、elseif cgi['comment'][0] == ""などという条件を入れるとInternalServerErrorになってしまうのだ。単独でやれば大丈夫なのだが、elseifにすると駄目だ。何なんだ、これは。どういうことだかさっぱり判らないぞ。

Tue, 19 Sep 2006 13:33:22 GMT

【Javascript練習帳】

訳が判らない

 Javascriptってのは訳が判らない。PHPとかRubyなら何となく判るのだが。しかし、今日はどうしても画像を移動させたくなった。今までひたすら文字情報だけを追究して、画像を忌み嫌っていたのだが、突然本の表紙画像を動かしたくなったのだ。わらわらと本の表紙画像が画面に現れたり、大量の表紙画像が上から降ってきたりしたら嬉しいのではないかと思ったのである。思ってしまったのだから、仕方がない。理由なんて知らない。調べてみると、画像を勝手に移動させたりするのはJavascriptという仕組みを使うらしい。PHPやRubyじゃできないのかと思ったが、どうやらできないらしい。何か参考書はないかと書棚を探してみると、『JavaScript & DHTMLクックブック』を持っているではないか。そういえば以前、買ってみたけれど訳が判らないので書棚に放り込んでおいたのだった。本の表紙画像を上から降らせるという例は載っていなかったが、直線上を動かすというのがあった。例は横の移動だったが、これを上から下にすれば、降ってくるようになるんじゃないかと本のページを睨みつけながら考えたわけだ。まずは素直に左から右へと動かしてみよう。
……
 判らない、どうにも判らない。この呪文のような文字の羅列は何なのだ。繰り返し呪文を唱えること数時間。やっと呪文が効くようになった。Amazon.co.jpからダンセイニの本の(もちろんダンセイニでなくてもいいのだが)書影を取得して、それをクリックを合図に右から左へと動かすだけのしょうもないページである。このページに埋め込もうと思ったが、明日か明後日には位置が変わってしまうので面倒臭い。そこで、別ファイルとした。できあがったしょうもないページはこちら。15インチの画面上で、幅8割くらいのウィンドウで開いてみるとちょうどよい位置になると思う。あまり大きい画面だとみっともない動きになってしまう。LinuxのFirefox、MacOSXのSafariとFirefoxでしか動作確認をしていない。万が一、ちゃんと動かなくても、何の損もしないのでそんなにがっかりしないでいただきたい。そのうち、わさわら降らせますから(いや、できないかも)。

_ Amazon.co.jp
JavaScript & DHTMLクックブック
オライリージャパン (2004/01)
¥ 4,830 (税込み)
在庫あり
Mon, 18 Sep 2006 13:26:47 GMT

【Ruby練習帳】

気がついたら

 自動更新されていた! 昨夜のことでしたがね。河出書房新社近刊図書RSSのことです。次は何を作ってみようか。

【Ruby練習帳】

塩基配列を探す

 なぜかエラーが出てインストールできなかったBioRuby 1.0.0

  % ruby install.rb config
  % ruby install.rb setup
  % sudo ruby install.rb install
で問題なくインストール。あのエラーは何だったのだろう。これで気分が良くなったので、長い塩基配列のなかから特定の短い配列を見つけるスクリプトを作ってみる。grepでいいんじゃないかと思うかも知れないが、塩基配列なので、相補鎖も同時に調べないと意味がないのだ。今月4日のスクリプトをBioRubyを使って書き換えた(というよりも書き加えたと云った方がいいか)。
require 'bio'
q_seq = Regexp.new(ARGV[1])
data = ""

File.open(ARGV[0]){|file|
while line = file.gets do
  if (/\A>/=~ line) == nil
    line.chomp!
    data.concat(line)
  end
end
}

len = data.length

naseq = Bio::Sequence::NA.new(data)
c_seq = naseq.complement

startpos = 0
while position = naseq.index(q_seq,startpos) do
   if position != nil
     result = naseq[position-25, 60]
     print result.sub(q_seq){|s| " " + s + " "}
     print " "
     p position
     startpos = position + 1
   end
end

startpos = 0
while position = c_seq.index(q_seq,startpos) do
   if position != nil
     result = c_seq[position-25, 60]
     print result.sub(q_seq){|s| " " + s + " "}
     print " c"
     p len - position
     startpos = position + 1
   end
end
まず、FASTA配列の第一列の
>gi|25307955|gb|AE007317.1| Streptococcus pneumoniae R6, complete genome
などという文字列も一緒に取り込まれているのに気づいたので、
 if (/¥A>/=~ line) == nil
という一行を追加し、行頭に>がある場合は取り込まないようにした。
 あとで、位置を表示するときに相補鎖は全体の長さから見付けた位置を引かないと判りにくいので、
 len = data.length
で全体の塩基数を出してから、
 p len - position
とやって位置を表示するようにする。
 相補鎖の配列を取得するのにBioRubyのcomplementを利用している。
 パリンドローム構造だったらどちら側からでも当たるはずだから、試しにGGAGG..CCTCCという配列を調べみる。「..」はGATCのどの塩基でもいいということ。
$ ruby testbio1.rb AE007317.fna ggagg..cctcc
cccgtattccagcaggtgttctttt ggagggacctcc ggggacaggtaagactttgcttg 12847
agcaagcaaagtcttacctgtcccc ggaggtccctcc aaaagaacacctgctggaatacg c12859
という結果が得られて、位置も合っている。数値が一致しないのは標的配列の塩基数分である。BioRubyの機能を使っているのは、「c_seq = naseq.complement」ということろだけ。ちょっと自分の探したい配列があるかどうかを見つけたいというときに使う手頃なものがなかったので、ちょっと嬉しい。私が気づいていないだけで、みんな知っているのがあるのかも知れないが、私はこれでとりあえずいい。ちなみにこれは、複数のFASTA配列を含むファイルを検索対象にするのには不向きです。

【Ruby練習帳】

rhtmlの認識

 昨日書いたように、私のubuntuではrhtmlファイルをどうしてもerubyで実行してくれない。ところが、

# for Apache::ERubyRun
  RubyRequire apache/eruby-run

  # handle files under /eruby as eRuby files by eruby.
  <Location /eruby>
    SetHandler ruby-object
    RubyHandler Apache::ERubyRun.instance
  </Location>

  # handle *.rhtml as eruby files.
  <Files *.rhtml>
    SetHandler ruby-object
    RubyHandler Apache::ERubyRun.instance
  </Files>
という記述をruby.loadの
LoadModule ruby_module /usr/lib/apache2/modules/mod_ruby.so
の後ろに追加してみると、昨日書いたようにxx.rhtmlは、「次のファイルを開こうとしています」という警告が出るだけで、画面を見せてくれない。ところが、/var/wwwにerubyというディレクトリ(フォルダ)を作り、確認用ファイルを置いて、拡張子をhtmlとかrbとかにしてみるとちゃんと動くではないか! しかし、rhtmlにすると駄目。何なのだ。拡張子をrhtmlにさえしなければ動くのだ。納得できないが、動くことは動く。
 でも、ここにファイルの出し入れをするのは管理者権限が必要だし、デスクトップから遠いので、public_htmlの中にerubyというフォルダを作って、
  <Location /~lege/eruby>
    SetHandler ruby-object
    RubyHandler Apache::ERubyRun.instance
  </Location>
という設定を追加(legeはユーザ名)すると、目的どおりの動きをするようにできた。しかし、rhtmlにすると駄目。何なのだ。練習用だから、まあいいか。それにしても、ずいぶん時間を使ってしまった、こんなことに。

Sat, 16 Sep 2006 05:51:27 GMT

【Ruby練習帳】

erubyとmod_rubyのインストール

 少しrubyにも慣れてきたから、erubyでウェブ・ブラウザに表示させることも始めようと決意しました。すっかり涼しくなった秋の朝のことでした。ubuntuはsynapticで簡単にerubyもmod_rubyもインストールできる。素晴らしい。ということでいとも簡単に両者ともインストール。apacheの設定を書き換えようと思って困った。どこに書けばいいのだ。Debian系は馴染がないのでよく判らないのだ。mod_ruby.loadに付け加えたのだけど、うまく動かない。端末ではerubyはちゃんと動くのでそちらの問題ではなく、もうapacheの設定だけだろう。apache2.confに書き込んでみたり、新たにmod_ruby.confなんてのを作ってみたりしたが、できない。ブラウザは画面を表示する代わりにファイルをダウンロードしますかと訊いてくる。もう何十回設定を書き換え、apacheをrestartしたことだろう。おかげで一日仕事が捗らなかった。

 悔しいのでVine Linux 3.2にインストールしてみた。Vineでも両者ともSynapticでインストールできるが、Apacheはソースからインストールしているので、erubyのみSynaptic経由でインストール。mod_rubyはmodruby.netから1.2.6をダウンロードして、

./configure.rb --with-eruby --with-apxs=/usr/local/apache2/bin/apxs
make
make install
としたが、--with-erubyは不要だったようだ。httpd.confのLoadModuleがたくさん並んでいるところに、
LoadModule ruby_module modules/mod_ruby.so
を加え、
<IfModule mod_ruby.c>
  RubyRequire apache/eruby-run

  <Location /eruby>
  SetHandler ruby-object
  RubyHandler Apache::ERubyRun.instance
  </Location>

  <Files *.rhtml>
  SetHandler ruby-object
  RubyHandler Apache::ERubyRun.instance
  </Files>
</IfModule>
というのを最後の方に追加した。今回は「<Location /eruby>」の部分は必要なかったが、まあいいや。

apache2を再起動し、問題なくrhtmlファイルが期待通りの画面をブラウザに提示したことを確認。

 さて、今度はMacOSXである。こちらはerubyもmodruby.netから1.0.5をダウンロードしなければならない。通常通り、

./configure.rb
make
make install
だけで簡単にインストール完了。次はmod_rubyだが、私は標準搭載のapacheではなくて、2.0系を別に入れて使用しているので、./configure.rbだけだと使っていないほうへインストールされてしまう。そこで、
./configure.rb --with-apxs=/Library/Apache2/bin/apxs
make
make install
としてインストール。httpd.confには、「LoadModule ruby_module modules/mod_ruby.so」と、
<IfModule mod_ruby.c>
      RubyRequire apache/eruby-run
     <Files *.rhtml>
      SetHandler ruby-object
      RubyHandler Apache::ERubyRun.instance
     </Files>
</IfModule>
を追加(今度は後半だけ)。こちらもapacheを再起動して、問題なくrhtmlが提示する画面を確認できた。こんな簡単にできるのに、ubuntuはどうなっているんだ!

【ubuntu】

OpenOffice.orgが……

 オレンジ色の瞬きにしたがっていくつかアップデート。再起動後にOpenOffice.org2が立ち上がらなくなってしまった。大事な書類を出さなければならないのに、書きかけの文書を完成させることができなくなってしまう。困る。仕方がないのでアップデートをしていない隣の部屋のubuntuを使って文書を完成させ、印刷した。もうVine 4.1が出たら乗り換えようかな。

Fri, 15 Sep 2006 14:05:04 GMT

【ruby/MacOSX】

いろいろインストール

 何としてもMacOSXでHyperEstraierの検索結果をkwic表示したい。諦める訳にはいかない。私はそのためにPowerMac G5を買ったのではなかったか(そんなわけはない)。ところが、HyperEstraier附属のrubynativerubypureをコンパイルしようとしても、makeで、

can't find header files for ruby.
make: *** [all] Error 1
というエラーが出てしまう。header filesがないのかあ。ということで、ruby最新版(1.8.5)をソースからインストールすることに。
./configure --prefix=/usr
make
make test
sudo make install
make clean
と云われるがままに実行してみると、難なく成功。HyperEstraierも再インストールすることにした。qdbmがなぜかないので(前にインストールしたはずなのに!)これを先に再インストール。続いてHyperEstraier。これも成功。ところが、rubynativeは、make installのところで、
mkdir -p /usr/lib/ruby/site_ruby/1.8
( cd src && cp -Rf estraier.so /usr/lib/ruby/site_ruby/1.8 )
cp: estraier.so: No such file or directory
make: *** [install] Error 1
というエラーが出てしまう。なぜ?
 そこで、rubypureをインストール。こちらは成功。なのになぜrubynativeは駄目なんだ! 何となくcd srcで中に入ってからmake installしてみたら、
$ sudo make install
/usr/bin/install -c -m 0755 estraier.bundle /usr/lib/ruby/site_ruby/1.8/powerpc-darwin8.7.0
ということになりestraier.bundleというファイルがインストールされた模様。こんなことどこにも書いていないんですけど、どういうことなんでしょうか。
 早速昨日と同様に、ruby estkwic.rb '水菓子'とか打ち込んでみると、「データベースエラー!」と云われてしまったので、casketフォルダを削除してから、インデックスの作成をやり直す。
estcmd gather -il ja -sd casket /Library/Apache2/htdocs/aozora
こんな具合。量が多いので時間がかかる。ようやくインデックスの作成が終って、再度検索すると……できた! あっという間に5087個のファイルを検索して結果を出したではないか。
$ ruby estkwic.rb '水菓子'
URI: file:///Library/Apache2/htdocs/aozora/%E3%81%AA%E3%81%A4%E3%83%BB%E5%A4%8F%E7%9B%AE%E6%BC%B1%E7%9F%B3%EF%BC%8896%EF%BC%89/%E5%A4%A2%E5%8D%81%E5%A4%9C.txt
被《かぶ》って、夕方になると 水菓子 屋《みずがしや》の店先 451
通らない時は、往来を見ないで 水菓子 を見ている。水菓子には 733
を見ないで 水菓子 を見ている。水菓子にはいろいろある。水蜜 760
と云っている。商売をするなら 水菓子 屋に限ると云っている。 1144
も、かつて銭《ぜに》を出して 水菓子 を買った事がない。ただ 1417
ょうと云って、女といっしょに 水菓子 屋を出た。それぎり帰っ 2339
URI: file:///Library/Apache2/htdocs/aozora/%E3%81%B2%E3%81%8F%E3%82%99%E3%83%BB%E6%A8%8B%E5%8F%A3%E4%B8%80%E8%91%89%EF%BC%8814%EF%BC%89/%E3%81%AB%E3%81%93%E3%82%99%E3%82%8A%E3%81%88.txt
座りなさいと手を取りて、あの 水菓子 屋で桃を買ふ子がござん 8774
URI: file:///Library/Apache2/htdocs/aozora/%E3%81%97%E3%81%BE%E3%83%BB%E5%B3%B6%E5%B4%8E%E8%97%A4%E6%9D%91%EF%BC%8832%EF%BC%89/%E5%AE%B6%EF%BC%88%E4%B8%8B%E5%B7%BB%EF%BC%89.txt
家の若主人が、東京に出て仮に 水菓子 屋を始めているとは。加 1230
。加《おまけ》に、若い細君が 水菓子 を売ると聞いた時は、榊 1308
話の様子では、普通《ただ》の 水菓子 を売る家の内儀《おかみ 1722
ゃ有りませんか。僕もネ、今の 水菓子 屋なぞはホンの腰掛です 3890
 本当は結果はもっと続く。ファイル名が見苦しいのはあとで考えよう。とにかく嬉しい。はいぱ〜えすとれいや〜〜〜と勝利の雄叫びをあげる私でした。

Thu, 14 Sep 2006 11:42:28 GMT

【Ruby練習帳】

また訂正

 10日に閉じ忘れを訂正した、あれ。よく見たら無駄な一行が。「result.grep(word){|final|」なんて書いているけれども、indexで調べたい単語の位置を決めているのだから、その語が含まれるのは当然、全く不要な一行である。

word = Regexp.new(ARGV[1])
nuc = "                    "

File.open(ARGV[0]){|file|
while line = file.gets do
    line.chomp!
    nuc.concat(line)
end
}

startpos = 0
while position = nuc.index(word,startpos) do
result = nuc[position-25, 60]
    print result.sub(word){|s| " " + s + " "}
    print " "
    p position
    startpos = position + 1
end
 これだけでいい訳ですね。

【Ruby練習帳】

HyperEstraierで全文検索

 そもそもこれがやりたくてRubyに手を伸ばしたのでした。すっかり忘れていましたよ。HyperEstraierという素敵な全文検索システムがあって、Ruby用のライブラリがあるのです。ところが私が愛用していたPHPのはないので甚だ悔しい思いをしていた訳です。
 どうしてHyperEstraier単独では不満で、Rubyと組み合わせたいかというと、Kwicである。HyperEstraier単独だと、調べたい語が含まれている文書を見つけるのにはいいのだが、調べたい単語の前後の状況を並べて判りやすく表示してくれる訳ではないからだ。だから、そんなに使用頻度の高くない言葉を含む文書を多数のファイルからHyperEstraierで抜き出して、それをRubyで整形して表示させたいのである。ubuntuでは簡単にHyperEstraierもRuby用ライブラリもインストールできる。HyperEstraierについてきた見本に、さっき訂正した整形スクリプトを組み合わせてこんなのを作ってみた。

 require "estraier"
 include Estraier
 
 word = Regexp.new(ARGV[0])

 # create the database object
 db = Database::new

 # open the database
 unless db.open("casket", Database::DBREADER)
   printf("error: %s\n", db.err_msg(db.error))
   exit
 end

 # create a search condition object
 cond = Condition::new

 # set the search phrase to the search condition object
 cond.set_phrase(ARGV[0])

 # get the result of search
 result = db.search(cond)

 # for each document in the result
 dnum = result.doc_num
 for i in 0...dnum
   # retrieve the document object
   doc = db.get_doc(result.get_doc_id(i), 0)
   next unless doc
   # display attributes
   uri = doc.attr("@uri")
   printf("URI: %s\n", uri) if uri
   title = doc.attr("@title")
   printf("Title: %s\n", title) if title
   # display the body text
   doc.texts.each do |text| 
     contents = text.gsub(/(?:\r|\r\n|\n)\z/, "").gsub(/ /, "")
     contents = "                               " + contents
     startpos = 0
     while position = contents.index(word,startpos) do
       if position != nil
         kwic = contents[position-42, 84]
         print kwic.sub(word){|s| " " + s + " "}
         print " "
         p position
         startpos = position + 1
       end
     end
   end
 end

 # close the database
 unless db.close
   printf("error: %s\n", db.err_msg(db.error))
 end
これをestkwic.rbという名前で保存して、「だけど」という語を探すときには、ruby estkwic,rb 'だけど' と打ってみる。すると、
$ ruby rubytest5.rb 'だけど'
URI: file:///home/ynakano/ruby_test/kwic_test/oa050409.htm
いつ、この通りを通るはずなん だけど なー、なかなか通んない 233
?女私、病気で死んじゃったん だけど ね、どうしても私を裏切 5285
・それで道で待ち伏せしてたん だけど ね。男しかし、地球人っ 6815
んでしょ。だから用意してたん だけど 。男おー、地球の食事っ 8086
!女ただのハムエッグとサラダ だけど ね。男ハムエッグとサラ 8176
URI: file:///home/ynakano/ruby_test/kwic_test/oa050226.htm
言ってたら気がまぎれていいん だけど ・・・一人で店じまいし 1111
何かが始まるぞって期待するん だけど 、何も起きなくてさ、ま 3154
の写真を見せてね、一億二千万 だけど 売れないから思い切って 6946
たら、ふらーっとなるばい。女 だけど その人、山川って名前な 7378
けどその人、山川って名前なん だけど 、いくつだと思う?男は 7423
今から新幹線で大阪まで行くん だけど 手元に現金が無いから持 7791
詐欺の一種たいなー。女お金も だけど 心動かされた自分が情け 8410
URI: file:///home/ynakano/ruby_test/kwic_test/oa050528.htm
一生懸命に思い出そうとしたん だけど 、どうしてもその部分だ 3388
めないだろう?涼子そりゃそう だけど ・・・・。あ〜あ、なん 4052
!と思い出せそうな気がするん だけど なぁ。幸一じゃあ連想テ 4169
という具合に一応目的通りの結果を表示してくれた。嬉しい!
 検索対象は福岡のラジオで放送された「土曜ドラマ館」のシナリオ2005年分。試しただけなので、検索対象としては小さいものである。シナリオの改行とか空白が削除されてべたっと繋がっているので、ちょっと変な感じがするが、お許し願いたい。
 英語の文章を検索するときは、「.gsub(/ /, "")」というのは消す。そうしないと、単語の区切りのスペースが消えてしまうから。日本語の場合、余計な1バイトのスペースが入っていないのなら、これは不要。職場のubuntuでおよそ2000の論文から調べたい語を並べるのに成功した。一瞬で結果が出るが、これはPHPで一つずつファイルを開いては検索して閉じていってもできなくなはい数だ。本当に探したいのは、自宅の「青空文庫全ファイル」を検索対象にする検索だ。ところが、前は簡単にコンパイルできたHyperEstraierが今日はエラーが出てしまう。Ruby用ライブラリも同様。なぜだっ、と虚しく夜空に叫んでみる。悲しい。

【Ruby】

買った本
 

Rubyにも少しだけ慣れてきたような気がするので、もう一冊本を買ってみた。Ruby on Railsの本。手に取ってみて、字が多くて説明が丁寧なような印象を受けたので、コンピュータ店のポイントで入手。私にもRailsが使える日が来るだろうか。

_ Amazon.co.jp
Ruby on Rails入門
秀和システム (2006/08)
¥ 2,940 (税込み)
通常24時間以内に発送

Wed, 13 Sep 2006 12:25:10 GMT

【Ruby練習帳】

思わず……

 手で更新してしまいました。cronで自動実行するかどうかの確認をしなければならないのに、河出書房新社の近刊情報ページが更新されたのを知ったので、ついruby kawade.rbとか打ち込んでしまって……。なんて莫迦なんだ。

【PHP/Perl】

迷っている本

『Perl→PHPらくらく移行ガイド』っていう本を見つけたんですがね、この反応は可逆なんでしょうか。「どちらか一方しか知らなくても、無理なくもう片方の言語を習得できるよう工夫。」ということは、PHPしか知らなくても、Perlが判るようになるんでしょうか。だとしたら、買ってみたい。でも、今はRubyに集中したいという気持もあるし。どうしよう。

_ Amazon.co.jp
Perl→PHPらくらく移行ガイド
毎日コミュニケーションズ (2006/09)
¥ 2,940 (税込み)
通常24時間以内に発送
Tue, 12 Sep 2006 12:37:26 GMT

【Ruby練習帳】

またもや実行されず

 なぜなんだ! 今度はちゃんと動くと思ったのに。

 あれ? 新しいファイルが保存されてゐないのに、FTPでプロバイダ上のファイルは書き換へられているようだ。これまた、なぜだ! どうなっているんだ!

【Ruby/ubuntu】

BioRuby

 ubuntuはシステムのアプリケーション管理でBioRubyをインストールできるではないか。これには驚いた。でもちょっとヴァージョンが古い。0.6だか何か。最新版は1.0.0だというのに。使えないよりはずっといいのだけど。

Mon, 11 Sep 2006 14:28:34 GMT

【Ruby練習帳】

closeはどこに

 閉じ忘れていましたよ。ドアとか水道の蛇口ではなくて、ファイルです。まあ、Rubyの話題なんで普通そうでしょうけどね。今月4日の塩基配列を正規表現で検索するスクリプト、よく見れば(よく見なくてもすぐに判りますが)、ファイルを開いたまま閉じていないではありませんか。みっともないので、書き直してみました。これでいいでしょうか。

word = Regexp.new(ARGV[1])
nuc = "                    "

File.open(ARGV[0]){|file|
while line = file.gets do
    line.chomp!
    nuc.concat(line)
end
}

startpos = 0
while position = nuc.index(word,startpos) do
result = nuc[position-25, 60]
result.grep(word){|final|
    print final.sub(word){|s| " " + s + " "}
    print " "
    p position
}
startpos = position + 1
end
 動かしてみたら、前と同様の結果を返してくれました。練習だから実際にはほとんど使わないのだけど、大事なことを忘れたままに放置しているのはみっともないし、練習になりませんからね。書き変えたっていったって「close」がないじゃないかよと呆れている方もいらっしゃるかも知れませんが。ちゃんと「 }」で閉じていますので、ご安心を。

【Ruby練習帳】

実行されなかった!

 昨日の河出書房新社近刊情報RSS、夜11時を過ぎてわくわくしながら確認してみたところ、実行された形跡がないではありませんか。うー、なぜなんだーと泣きながら涙で歪むモニタ画面を睨みつけていたら気づきました。ruby kawade.rbなんてコマンドを打ち込む訳ではないので、ファイルに実行権を与え、スクリプトの第一行に「#! /usr/bin/ruby」って書いておかなければならないのを忘れていたのです。今晩の11時に再度挑戦です。

【Ruby練習帳】

エディタに悩んでみる

 MacOSXでPHPを書くときにはいつもmiを使っているのですが、これにRubyモードを追加してみたものの、残念ながら私の目にはあまり見やすくないのでした。JeditにRubyカラーを導入してみると、なかなかすっきりしていますが、ものたりないのですね(勝手なことばかり云ってすみません)。結局、iTerm上でvimを使おうかなと思っているところです。
 こんな感じ↓

Ruby編集画面
Sun, 10 Sep 2006 02:47:58 GMT

【Ruby練習帳】

河出書房新社近刊情報RSS改良版

 昨日の河出書房新社新刊情報取得スクリプトを改良した。新しいものが上に来るようにするには、
line.each{|elem|
のところを
line.reverse.each{|elem| とするだけで簡単に解決できた。新刊情報らしくなったような気がする。

 自分で使うだけならこれで完了だが、人にも利用してもらいたいとか、自分も外出先からも参照したい(そんなことがあるかどうかは知らないが)と思うかも知れないので、サーバに置くことにしよう。自宅サーバを持っている人は簡単だが(実は私は持っている)、プロバイダの自分のファイル置き場に転送するのが面倒臭いので、その機能も組み込むことにする。
 最初に
require 'net/ftp'
としてから、

Net::FTP.open('ftp00.nifty.com') do |ftp|
  ftp.login('user_id', 'password')
  ftp.chdir('public_html')
  ftp.puttextfile('kawadenew.xml')
end
という5行を追加した。実際にはopen以下の括弧内に自分の契約しているプロバイダのftpサーバのアドレスを、login以下の括弧の中にユーザIDとパスワードを、chdir以下の括弧内にファイルを置くディレクトリを書く(ちなみにniftyはpublic_htmlではなくhomepageだ)。
 このスクリプトを実行すると、このスクリプトと同じフォルダ(ディレクトリ)にkawadenew.xmlというファイルを保存すると同時に、プロバイダの自分のサイトのファイル置き場へとkawadenew.xmlを送り込む。試してみたら、本当に動いて、新しいファイルが保存されていた!

 さて、毎日自分で実行させてもいいのだけど、疲れて忘れたりすることもあるかも知れないから、自動的に実行するように設定しよう。MacOSXとかLinuxでは/etcにcrontabというファイルがあって、ここに指示を書き込めば定期的に実行してくれる。ファイルの自動バックアップなんかを設定しておくと便利で、私もそうしている。ただ、このPowerMac G5は24時間運用ではないので、何時に設定しようかちょっと悩んだ。毎晩10時にはバックアップを実行するので、11時にしようか。ということで、

00 23 * * * root /Users/nakano/Sites/kawade/kawade.rb 
と書き込む。root権限で毎晩11時に実行する。もしかしたら、rootじゃない方がいいのかな。よく判らない。しばらく様子をみてみよう。この河出書房新社近刊・新刊情報RSSは以下のURLで公開した。ちゃんと動けば毎晩更新される。
http://homepage3.nifty.com/~ynakano/kawadenew.xml

 最終的に出来上がったものは以下のとおりである。

require 'open-uri'
require 'iconv'
require 'rss/2.0'
require 'net/ftp'

rss = RSS::Rss.new("2.0")
chan = RSS::Rss::Channel.new
chan.title = "RSS for Kawade forthcomming books"
chan.description = "Kawade forthcomming books"
chan.link = "http://www.kawade.co.jp/np/forthcoming.html"
chan.language = "ja"
rss.channel = chan
conv = Iconv.new("UTF-8","Shift_JIS")

open('http://www.kawade.co.jp/np/forthcoming.html') do |f|
  line = f.read.split(/detailCopy/)
  line.shift
  line.reverse.each{|elem|
    ipos = elem.index('/isbn/')
    isbn = elem[ipos+6,10]
    tpos2 = elem.index('/STRONG',ipos)
    title = elem[ipos+18,tpos2-ipos-23]
    title = conv.iconv(title)
    dpos = elem.index('<STRONG>')
    pubdate = elem[dpos+8,10]
    apos1 = elem.index('/author/')
    if apos1 == nil
      description = pubdate
    else
      apos2 = elem.index('/SPAN',apos1)
      author = elem[apos1+15, apos2-apos1-24].gsub(/<.*?>/m, "").gsub(/>\//,"")
      author = conv.iconv(author)
      description = author + " (" + pubdate + ")"
    end

    item = RSS::Rss::Channel::Item.new
    item.title = title
    item.link = "http://www.kawade.co.jp/np/isbn/" + isbn
    item.description = description
    chan.items << item
  }
end

File.open("kawadenew.xml", "w+"){|file|
  file.puts(rss.to_s)
}

Net::FTP.open('ftp00.nifty.com') do |ftp|
  ftp.login('user_id', 'password')
  ftp.chdir('public_html')
  ftp.puttextfile('kawadenew.xml')
end

気が変わりました!

 本文が著者名と刊行予定日だけでは寂しいので、判型とか値段とかも入るようにしてみました。
require 'open-uri'
require 'iconv'
require 'rss/2.0'
require 'net/ftp'

rss = RSS::Rss.new("2.0")
chan = RSS::Rss::Channel.new
chan.title = "RSS for Kawade forthcomming books"
chan.description = "Kawade forthcomming books"
chan.link = "http://www.kawade.co.jp/np/forthcoming.html"
chan.language = "ja"
rss.channel = chan
conv = Iconv.new("UTF-8","Shift_JIS")

open('http://www.kawade.co.jp/np/forthcoming.html') do |f|
  line = f.read.split(/detailCopy/)
  line.shift
  line.reverse.each{|elem|
    ipos = elem.index('/isbn/')
    isbn = elem[ipos+6,10]
    tpos2 = elem.index('</STRONG>',ipos)
    title = elem[ipos+18,tpos2-ipos-22]
    title = conv.iconv(title)
    dpos = elem.index('<STRONG>')
    pubdate = elem[dpos+8,10]
    desc1 = elem.index('</DIV>',tpos2)
    description = elem[tpos2, desc1-tpos2].gsub(/<.*?>/m, "")
		.gsub(/\207U/, "").gsub(/\s+/, " ")
    description = conv.iconv(description)
    description = description + " (" + pubdate + ")"

    item = RSS::Rss::Channel::Item.new
    item.title = title
    item.link = "http://www.kawade.co.jp/np/isbn/" + isbn
    item.description = description
    chan.items << item
  }
end

File.open("kawadenew.xml", "w+"){|file|
  file.puts(rss.to_s)
}

Net::FTP.open('ftp00.nifty.com') do |ftp|
  ftp.login('user_id', 'password')
  ftp.chdir('public_html')
  ftp.puttextfile('kawadenew.xml')
end
Sat, 09 Sep 2006 05:28:34 GMT

【ubuntu】

BioRuby

 ubuntuにBioRubyをインストールしようとした。そろそろちゃんと仕事に使おうかと思ったわけだ。ダウンロードした圧縮ファイルを展開し、ruby install.rb config → ruby install.rb setup → sudo ruby install.rb installとやったらエラーが出てしまった。最初のconfigのところである。rubyに馴染の薄い私には何が起こったのだか全く理解できない。茫然と涙を流すだけである。
 帰宅してから、PowerMac G5で試したみたら簡単にインストールできた。家でインストールに成功してもあまり使わないのだけど。

【Ruby練習帳】

河出書房新社近刊情報RSS

 昨日の河出書房新社新刊情報取得スクリプトを発展させてRSS作成スクリプトにしてみよう。こんなふうに書いてみた。

require 'open-uri'
require 'iconv'
require 'rss/2.0'
rss = RSS::Rss.new("2.0")
chan = RSS::Rss::Channel.new
chan.title = "RSS for Kawade forthcomming books"
chan.description = "Kawade forthcomming books"
chan.link = "http://www.kawade.co.jp/np/forthcoming.html"
chan.language = "ja"
rss.channel = chan
conv = Iconv.new("UTF-8","Shift_JIS")

open('http://www.kawade.co.jp/np/forthcoming.html') do |f|
  line = f.read.split(/detailCopy/)
  line.shift
  line.each{|elem|
    ipos = elem.index('/isbn/')
    isbn = elem[ipos+6,10]
    tpos2 = elem.index('/STRONG',ipos)
    title = elem[ipos+18,tpos2-ipos-23]
    title = conv.iconv(title)
    dpos = elem.index('<STRONG>')
    pubdate = elem[dpos+8,10]
    apos1 = elem.index('/author/')
    if apos1 == nil
      description = pubdate
    else
      apos2 = elem.index('/SPAN',apos1)
      author = elem[apos1+15, apos2-apos1-24].gsub(/<.*?>/m, "").gsub(/>\//,"")
      author = conv.iconv(author)
      description = author + " (" + pubdate + ")"
    end

    item = RSS::Rss::Channel::Item.new
    item.title = title
    item.link = "http://www.kawade.co.jp/np/isbn/" + isbn
    item.description = description
    chan.items << item
  }
end

File.open("kawadenew.xml", "w+"){|file|
  file.puts(rss.to_s)
}
 このファイルをhttpdサーバが見せたいファイルを置く場所に入れて実行させるとkawadenew.xmlというファイルを作り出す。これがRSS2.0の書式に従って作成されたファイルである。RSSリーダで開くと下のようになる(これはMacOSXのSafariで開いたところ。上の部分だけ)。
河出近刊リストRSS

 このRubyのスクリプトをcronで定期的に実行させれば自動的に更新される立派なRSSになる。ただ、このRSSを人に見せたいと思ったら、自前のサーバを持っていない場合は、プロバイダか何かのサーバにアップしなければならない。そこまで自動でやってほしいものだ。
 素敵なものを作ってしまったと自己満足に浸っていたら、どうも変な気がしてきた。何か間違っている、このRSSは。しばらく見つめていたら気がついた。古い情報が上にあるのだ。これだと新しい情報は一番下に追加されてしまう(かも知れない)。RSSリーダの設定にもよるが、普通はそういうことになってしまうはずだ。一旦、配列に取り込んでおいて、あとでまとめてひっくり返せばいいのかな。PHPではそうやっているのだが。

Fri, 08 Sep 2006 12:33:50 GMT

【ubuntu】

amazon-rubyのlocale

 昨日、Amazon.co.jpから日本語の本の検索結果が得られたのは実はMacOSXからであった。Ubuntuでやってみたら、どうもlocale =JPという設定が有効にならないようなのだ。システムからインストールされるAmazon-rubyが0.9.0-2だったので、これを外して 0.9.2にしてみたが、結果は同じ。何かの作業に支障を来すわけではないが、どうも納得できない。なぜだ!

【Ruby練習帳】

河出書房新社新刊情報取得スクリプト再び

 Amazonが思うようにいかず甚だ不愉快なので、先日ISBNを取得しただけで放置しておいた河出書房新社近刊情報リスト取得に手を付けることにした。
 文字コードをUTF8にしたのは、後でRSSに使おうかと考えているから。こう書くと簡単に作ったように見えるが、いろいろ困ったりしていたのだ。特に文字コードの扱いは。

require 'open-uri'
require 'iconv'
conv = Iconv.new("UTF-8","Shift_JIS")

open('http://www.kawade.co.jp/np/forthcoming.html') do |f|
  line = f.read.split(/detailCopy/)
  line.shift
  line.each{|elem|
    ipos = elem.index('/isbn/')
    isbn = elem[ipos+6,10]
    print isbn + " 『"
    tpos2 = elem.index('/STRONG',ipos)
    title = elem[ipos+18,tpos2-ipos-23]
    print conv.iconv(title) + "』"
    apos1 = elem.index('/author/')
    if apos1 == nil
      print "\n"
    else
      apos2 = elem.index('/SPAN',apos1)
      author = elem[apos1+15, apos2-apos1-24].gsub(/<.*?>/m, "").gsub(/<\//,"")
      puts conv.iconv(author)
    end
  }end
 著者の表示があまり整っていないが、もう面倒臭い。あと価格と刊行予定日を取得して、河出書房新社新刊情報RSSでも作ろうか。PHPではもうできているのだが。結果表示はこんな感じである。
4309951449 『ディズニープリンセス vol.24 2006年10-11月号  』
4309017789 『浮世でランチ』山崎 ナオコーラ
4309243916 『心理学論文の書き方』松井 豊
4309243932 『性犯罪の心理』作田 明
4309269168 『大人の塗り絵 秋の花編』佐々木 由美子
4309280641 『かぎ針1本でできる! あみぐるみcollection VOL.5』河出書房新社編集部
430928065X 『ハワイアン布でつくるカルトナージュ』駒澤 由美子
4309280676 『こどもニットの本』渡部 サト
4309715656 『マックス・エルンスト』サラーヌ・アレクサンドリアン 著 大岡 信 訳 マックス・エルンスト
4309252052 『世界でいちばん良い医者に出会う「患者学」』小林 一哉 著 前田 稔
 本当はもっと長い。著者が複数いるときに、ちょっと変な感じになってしまう。どうすればいいんだろう。

Thu, 07 Sep 2006 13:38:50 GMT

【Ruby練習帳】

余計なif

 4日の文字列検索スクリプトでは「if position !=nil」と一つ目の「end」が余計だった。その前の日の条件がそのまま残っていました。この条件はwhile以下に含まれています。

【Ruby練習帳】

Amazon.co.jpで検索してみたが

 Ruby/Amazonをインストールして、Amazon.co.jpで検索してみた。

require 'amazon/search'
dev_token = "xxxxxxxxx"
locale = 'jp'
keyword = ARGV[0]

  req = Amazon::Search::Request.new(dev_token,locale)
  res = req.keyword_search(keyword, 'books', Amazon::Search::LITE) { |product|
    print product.asin + " "
    puts product.product_name
  }
 練習なので表示させるのはISBNと書名のみ。これをamz.rbという名で保存して、
$ ruby amz.rb ロード・ダンセイニ
と打ち込んでみたら、
4480028668 魔法使いの弟子
415020005X ペガーナの神々
4309462545 時と神々の物語
4309462634 最後の夢の物語
4309462421 世界の涯の物語
4480021515 短篇集 妖精族のむすめ
4309462472 夢見る人の物語
4150200475 魔法の国の旅人
4150200300 魔法使いの弟子
4480025588 影の谷物語
と表示された。なるほどねえ。これをどう使おうか、まだ検討中。
 今日は昨日届いたRuby Cookbookと、この本も参考にしてみた。

_ Amazon.co.jp
ライド・オン・Rails
ソフトバンククリエイティブ (2006/6/30)
¥ 3,129 (税込み)
通常24時間以内に発送
Wed, 06 Sep 2006 13:41:50 GMT

【ubuntu】

gd.soだったか!

 phpでgdを使うためにphp5-gdをインストールしたのに、全然有効にならない。いろいろ余計なものをインストールしてしまったが、結局php.iniのextension=gd.soのところのコメントアウト#を外していなかったのだった。前は--with-gdでコンパイルしていたときはこんなことしなかったような気がするのだけど。慣れないと何でも難しい。

【Ruby】

買った本

 また本を買ってしまった。高いなと思いながら註文したのだが、これは分厚い。873ページもあるのだから当然だが。さまざまな状況に応じたいろいろな例が載っているので役立ちそう。日本語ならもっと判りやすかったのに。
 今悩んでいるのは実は日本語の処理なのだが、それはこの本には載っていない。

_ Amazon.co.jp
Ruby Cookbook
Oreilly & Associates Inc (2006/7/28)
¥ 5,201 (税込み)
通常24時間以内に発送
Tue, 05 Sep 2006 13:09:22 GMT

【Ruby練習帳】

ネットへ踏み出す

昨日のでは行の切れ目に求める配列があると見つけ出せないので、全部一列につないでから探すようにしてみた。改行コードを削除しながらconcatで全部つないで、文字列検索の開始点を、前に見付けた場所の次の位置からにして、どんどん先に進めていくというのはPHPで慣れているので簡単である。最初に20個の空白を置いているのは、探したい配列が最初の方にあったときのため。ついでに、行の右端に検索文字列の位置を表示させてみた。

filename = ARGV[0]
word = Regexp.new(ARGV[1])
nuc = "                    "
file = open(filename)

while line = file.gets do
    line.chomp!
    nuc.concat(line)
end

startpos = 0

while position = nuc.index(word,startpos) do
if position != nil
result = nuc[position-25, 60]
result.grep(word){|final|
    print final.sub(word){|s| " " + s + " "}
    print " "
    p position
}
startpos = position + 1
end

end
こんなふうに結果が出る。昨日よりも増えているから、ちゃんと行に跨る部分も拾っているようだ。ちなみに、正規表現で検索しているから、GAAとTTCで挟まれた4文字を見付けるとかいうこともできる。
CATTCTTTATACTTATAAGATTAAT AAGGAGGA AACTAACTGTGAAAATCCTATGCGAGA 1713
AACATTGAAGTAGTCAGTCTCTACC AAGGAGGA GGCCGGATATACTGTTTTGTCCGGAAA 32688
TCAGGCTGCACTAGACTCACCCGAC AAGGAGGA GTAGCGTGCGCAGAACGCGCGGCGAGA 71126
TTAGCAGCGGGGTTGCTCATCCTTC AAGGAGGA TTGAGAGTCCTGCCCTCAGGGTGTGCA 106809
TGCCCGGTACCCACTCCTTGTCGAC AAGGAGGA GGAAATCATCCCAGGAGAGGGATGTGA 107626
TTCCACCCTTTTTCCGAGAGGAAAT AAGGAGGA TGTGCACGATGCACGCGCTCATGCGTC 186529
AGTTTTTGGCTCGTGTTGATTTAAA AAGGAGGA CGAAATAATGCCAAAACAAGTAGTCGT 229250
CGAGCGTAGCAGCGAGTATGTATCC AAGGAGGA ATCCTCCCGTAGGGGCAAAAAGCGCGG 237045
 今度はオンライン情報を取得してみたくなった。そこで、河出書房の近刊情報を取りにいってみることにした。
require 'open-uri'

open('http://www.kawade.co.jp/np/forthcoming.html') do |f|
    line = f.read.split(/\/isbn\//)
    line.shift
    line.each{|elem|
      p elem[0,10]
    }
end
 たったこれだけである。練習だから。open-uriでhtmlファイルの内容を取得して、/isbn/という文字列で内容を分割して配列にする。最初の要素には書籍情報が入っていないので、array.shiftで先頭の要素を外して各要素の最初の10文字を表示させたら、近刊図書のISBNがずらりと表示された。うまくいったけど、全然面白くない。 結果はこんな感じ(実際にはもっと長い)。
"4309408095"
"4309408117"
"4309408125"
"4309408133"
"4309408184"
"4309462774"
"4309462782"
"430948090X"
 今日届いたこの本も少し参考にしてみた。

_ Amazon.co.jp
プログラミングRuby 第2版 言語編
オーム社 (2006/8/26)
¥ 3,990 (税込み)
通常24時間以内に発送
Mon, 04 Sep 2006 13:18:55 GMT

【Ruby練習帳】

KWICもどき

 週末になったのでRubyの練習である。今日はバクテリア・ゲノムの塩基配列の中から、調べたい配列を含む領域を抜きだして表示するものを作ってみよう。このゲノム配列は、1行70字のテキストファイルで、全部で300万文字ほどある。バクテリアなので、真核生物に比べると短いものである。
 ファイル名と調べたい塩基配列を打つと、その文字列を含む行を返して欲しいということと、求める文字列を中心にきれいに並べて欲しいという二点が今回の要求だ。まず、求める文字列を含む行を表示させるために、こんなものを書いた。

filename = ARGV[0]
word = Regexp.new(ARGV[1])
file = open(filename)
while text = file.gets do
	text.grep(word){|line|
		p line.sub(word){|s| "<" + s + ">"}
	}
end
file.close
 ターミナルに例えばruby test.rb AE000520.fna AAGGAGGAと打ち込んでみる。test.rbが上記のスクリプトのファイル名、AE000520.fnaが塩基配列のファイル名、AAGGAGGAが今回求める塩基配列である。ARGV[0]がファイル名、ARGV[1]が求める塩基配列として取り込まれる訳だが、「Regexp.new」というところが何だか判らない。そうすると動く(そうしないと動かない)のだけれど、馴染めないというか……。あとは一行ずつ取り込んでgrepで検索文字列が含まれているかどうかを判定して、検索文字列の両側に<と>を置いて強調してみた。
"CTTATAAGATTAAT<AAGGAGGA>AACTAACTGTGAAAATCCTATGCGAGAAAGAAGCCTTTCTGAAGGAAA\n"
"GACTGCGTCTGCATATACACTCATAACATTGAAGTAGTCAGTCTCTACC<AAGGAGGA>GGCCGGATATACT\n"
"CTCATAATAACTCCTATGGACGGCTCACCTTATCAGGCTGCACTAGACTCACCCGAC<AAGGAGGA>GTAGC\n"
"GGTGCTTGCTCCTCTTTAGCAGCGGGGTTGCTCATCCTTC<AAGGAGGA>TTGAGAGTCCTGCCCTCAGGGT\n"
"ACCCACTCCTTGTCGAC<AAGGAGGA>GGAAATCATCCCAGGAGAGGGATGTGAGCGCCTTCGCATCCTTGT\n"
"ATTAGTTCCACCCTTTTTCCGAGAGGAAAT<AAGGAGGA>TGTGCACGATGCACGCGCTCATGCGTCTGTTC\n"
 結果はこんな感じ(実際には30行くらいある)。括弧で挟んでも検索文字列がどこにあるのか判りにくい。もう少し何とかしたい。

 そこで、少し改良してみた。

filename = ARGV[0]
word = Regexp.new(ARGV[1])
file = open(filename)
while text = file.gets do
	line = "                   " + text
	position = line.index(word)
	if position != nil
		result = line[position-16, 40]
		result.grep(word){|final|
			p final.sub(word){|s| " " + s + " "}
		}
	end
end
file.close
 まず一行ずつ取り込んで、左側に空白を20個くっつける。これがないと後で困る。それから、検索語が出てくる位置を「index」で調べる。検索語が含まれていなければ「nil」が返ってきているはずなので、nilでなければ、その位置から16文字前の場所から40文字を抜きだし、さらに先ほどのスクリプトのときと同様に、grepとsubで検索語の両脇に空白を一個ずつ挿入して表示させる。さて、結果は、
"             CTTATAAGATTAAT AAGGAGGA AACTAACTGTGAAAATCCTATGCGA"
"ATAACATTGAAGTAGTCAGTCTCTACC AAGGAGGA GGCCGGATATACT\n"
"TATCAGGCTGCACTAGACTCACCCGAC AAGGAGGA GTAGC\n"
"CTTTAGCAGCGGGGTTGCTCATCCTTC AAGGAGGA TTGAGAGTCCTGCCCTCAGGGT\n"
"          ACCCACTCCTTGTCGAC AAGGAGGA GGAAATCATCCCAGGAGAGGGATGT"
"AGTTCCACCCTTTTTCCGAGAGGAAAT AAGGAGGA TGTGCACGATGCACGCGCTCATGCG"
となった。おお、前よりもずっと見やすいではないか。

 練習初日ではこんなところか。この練習の成果が実際の塩基配列の解析に役立つかというと残念ながらそんなことはなくて、求める配列が行をまたいでいると見つけ出せないので役立たずなのだ。一行一文に整形した普通の文章から、探したい用例を見つけるのには使えるかも知れない。いわゆるKWICである。長いテキストでも大丈夫(1.1MBだから大したことはない)だということで、塩基配列なんか使ったが、やはりここはダンセイニの『ペガーナの神々』を使ってみようか。「game」という言葉が出現する箇所を探してみると、

" regard with pale eyes the  game s of the small gods, and to w"
"ears passed over the first  game  of the gods.\n"
"ib grew weary of the first  game  of the gods, and raised his "
"ars passed over the second  game  of the gods, and still it wa"
"b grew weary of the second  game , and raised his hand in the "
"ds saw Kib playing his new  game  They came and played it too."
"he gods; We are the little  game s of MANA-YOOD-SUSHAI that he"
", saying: 'We now play the  game  of the gods and slay men for"
"ana's gods, and play Their  game  with men.'\n"
"med haunts, and played the  game  of Life and Death with fishe"
"the Worlds, nor any more a  game  for the small gods to play.\n"
"ods endure, and play their  game  with men.\n"
"th, for ye have played the  game  of the gods too long with th"
ちゃんと見つけて表示してくれた。でも、何か物足りないなあ。

 今日参考にしたのはこの本。

_ Amazon.co.jp
Rubyレシピブック
ソフトバンククリエイティブ (2004/05)
¥ 2,940 (税込み)
通常24時間以内に発送
Sun, 03 Sep 2006 08:16:18 GMT