2011年12月30日金曜日

前回(サーバからcsvを複数取得する)の続きに、取得したcsvをDBにinsertする

app/libの下にprice_importer.rbを作成し、app/で実行する

$ ruby script/runner PriceImporter.execute

以下の内容
require 'csv'
class PriceImporter
  class << self
    def execute()
      begin
          result = system("/path/to/script/getfile.sh")  #←<a href="http://kagen88.blogspot.com/2011/12/shelllftp.html">前回作成したshellスクリプト</a>
          print result
          Dir::glob("/path/to/data/*.csv").each {|f|  #←取得したcsvファイルを保存する場所の(すべての?)csvをループ
            puts "#{f}: #{File::stat(f).size} bytes"  #←サイズを表示してみる
            cf=File.open(f,"r")  #←開く
            buf=cf.read()  #←読む
            @parsed_file = CSV::Reader.parse(convertSjis2UTF8(buf))  #←CSVハッシュに格納、その前にsjisをutf8に
            @parsed_file.shift  #←最初のタイトル行をスキップ
            @parsed_file.each  do |row|
              pd = Product.find_by_code(row[0])  #←既存のテーブルモデルを使って、コードの有無を確認
              if pd
                Price.delete_all "pd_id = " + pd.id.to_s + " AND base_date_on = '" + row[4] + "'"  #←上書きしたいので、一致したレコードを削除
                p = Price.new
                p.pd_id = pd.id
                p.base_date_on = row[4]
                p.price = row[5]
                p.save  #←インサート
              else
                RAILS_DEFAULT_LOGGER.debug("コード(" + row[0] + ")がproductsテーブルに存在しない。ご確認ください。")
                puts "コード(" + row[0] + ")がproductsテーブルに存在しない。ご確認ください。"
              end
            end
          }
      rescue => e
        RAILS_DEFAULT_LOGGER.debug(e)
        raise
      end
    end
    def convertSjis2UTF8(val)←utf8変換
      val.kconv(Kconv::UTF8, Kconv::SJIS) unless val.blank?
    end
  end
end
以上

パスワードを埋め込みのshellスクリプト。lftpで複数ファイルをダウンロード

パスワードを埋め込みのshellスクリプト。lftpで複数ファイルをダウンロード。
sftpは必要(通常ある)、lftpがなければyumでインストル

$ yum install lftp

ダウンロードするファイル名はyyyymmddのワイルドカードですが,日付の正確性はチェックしない。
以下スクリプトの内容:

#!/bin/bash
#ローカル保存フォルダー
SAVE_FILE_DIR="~/downloaded"

#今日の日付のyyyymmddファイル、不採用なのではコメントアウト
#TARGET_FILE="DATA_$(date "+%Y%m%d").csv"

#ファイル名がDATA_yyyymmdd.csvのファイルをすべて
TARGET_FILE="DATA_[1-2][0-9][0-9][0-9][0-1][0-9][0-3][0-9].csv"

HOST=myhost
ACCOUNT=user
PASSWORD=pass

#まず既に存在していたら削除する
rm -f ${SAVE_FILE_DIR}/${TARGET_FILE}

#sftからダンロード
lftp -u ${ACCOUNT},${PASSWORD} sftp://${HOST} <<__LUCEN
lcd ${SAVE_FILE_DIR}
mget ${TARGET_FILE}
quit
__LUCEN

fileの存在するかどうかを判断するshell script

fileの存在するかどうかを判断するshell script

#!/bin/bash
if [ -f filename ]
then
echo "filename exists"
fi

2011年12月28日水曜日

fund_indicesは銘柄の基準価額、純資産や分配金の履歴テーブル、巨大なテーブルです。
やりたいことは重複なしでランダムで3銘柄IDを抽出したい。fund_idじゃなくidはプライマリーキーです。
fund_idは重複している。データ全部で280万くらい。

id fund_id as_of_date value
1 529 20111130 5394
2 529 20111129 5384
3 529 20111128 5323
4 529 20111125 5312
5 529 20111124 5312
6 529 20111122 5366
7 529 20111121 5397
8 545 20111129 5374
9 545 20111128 5373
10 545 20111125 5372
11 545 20111124 5312
12 545 20111122 5376
13 545 20111121 5377
... ... ... ...

mysqlのorder by rand()を使ったが、凄く遅い!なんと1分もかかります。

sql> select distinct fund_id from fund_indices order by rand() limit 3;

fund_idを絞るサブクエリを入れると凄く早くなった

sql> select fund_id from (select distinct fund_id from fund_indices) order by rand() limit 3;
表示中の列 0 - 2 (~31 合計, クエリの実行時間 0.0495 秒)



Excel vba シート追加、名前変更のエラー防止、「暴力」チェッカー

excelのシートいろいろ禁止文字が有るみたい、暴力的に禁止字を排除する
If trim(shtName) <> "" Then
  If Len(shtName) > 30 Then shtName = Left(shtName, 30)
  shtName = Replace(shtName, "/", "")
  shtName = Replace(shtName, "/", "")
  shtName = Replace(shtName, "[", "")
  shtName = Replace(shtName, "]", "")
  shtName = Replace(shtName, "*", "")
  shtName = Replace(shtName, "*", "")
  shtName = Replace(shtName, "¥", "")
  shtName = Replace(shtName, "\", "")
  shtName = Replace(shtName, ":", "")
  shtName = Replace(shtName, ":", "")
  shtName = Replace(shtName, "?", "")
  shtName = Replace(shtName, "?", "")
  ActiveWorkbook.Worksheets.Add(after:=Worksheets(Worksheets.Count)).Name = shtName
End If

2011年12月26日月曜日

選択されているRangeの行だけを配列で返すメソッド

選択されているRangeの行だけを配列で返すメソッド、
単一の長方形の選択範囲なら、Selection.addressで処理しても十分だと思いますが、
このメッソドは複数バラバラの選択範囲に対応します。まぁ、使う場面ないかもしれない…
Function getRowsFromRanges(ByVal seletedRange As Range) As Variant
  Dim cl As Range
  Dim arrRows As New Scripting.Dictionary
  For Each cl In seletedRange
    If Not arrRows.Exists(cl.row) Then
        arrRows.Add cl.row, ""
    End If
  Next
  getRowsFromRanges = arrRows.Keys
End Function

2011年12月22日木曜日

princeの日本語文字化けについて

前回centosにprince用msttcorefontsをインストル手順を紹介しました。それで一応PDFは吐き出されたけど、よく見たら、日本語はすべて文字化けている(「?」になっている)
まずはシステム上「明朝」や「ゴシック」などturetype fontの有無を確認、centosだと普通はこの場所にあるか

$ cd /usr/share/fonts/
$ ll
合計 24
drwxr-xr-x. 2 root root 4096 11月 1 17:05 2011 ipa-gothic←ゴシック
drwxr-xr-x. 2 root root 4096 11月 1 17:05 2011 ipa-mincho←明朝
drwxr-xr-x. 2 root root 4096 11月 1 17:05 2011 ipa-pgothic←Pゴシック
drwxr-xr-x. 2 root root 4096 11月 1 17:05 2011 ipa-pmincho←P明朝
drwxr-xr-x. 2 root root 4096 12月 21 16:19 2011 msttcorefonts←前回インストルしたMSフォント
drwxr-xr-x. 2 root root 4096 11月 1 17:05 2011 vlgothic

そしてfonts.cssを開いて。

$ sudo vi /usr/local/lib/prince/style/fonts.css
まずはもともと「font-family: serif」と「font-family: sans-serif」の@font-faceブロッグをすべて削除(またはコメントアウト)
そして明朝とゴシックを追加

/* standard "IPAMincho" font family */

@font-face {
font-family: serif;
font-style: normal;
font-weight: bold;
src: url("/usr/share/fonts/ipa-mincho/ipam.ttf")
}

/* standard "IPAGothic" font family */

@font-face {
font-family: sans-serif;
font-style: normal;
font-weight: bold;
src: url("/usr/share/fonts/ipa-gothic/ipag.ttf")
}

fontの絶対パスを設定すること

2011年12月21日水曜日

CentOS6(64bit)にmsttcorefontsをインストール

ちなみに、前回はprinceのインストール方法を紹介しました。必要があれば参照してください。

htmlをPDFに変換してくれるlib princeを使おうと思ったけど、「fontがない」と怒れる

$ /usr/local/bin/prince --input=html --server -s /home/kagen/work/anyproj/public/stylesheets/application.css -s /home/kagen/work/anyproj/public/stylesheets/print.css -s /home/kagen/work/anyproj/public/stylesheets/prince.css ~/test.html -o test.pdf
...
Fontconfig error: Cannot load default config file
...
msg|wrn||no glyphs for character U+0074, fallback to '?'
msg|err||no available fonts

問題は2つ有るようだ
①Fontconfigがない
②linux上msのtruetype fontがインストールされてないのが原因らしい。
解決
①について、インストールすればいいとおもう。

$ sudo yum install fontconfig

②の解決策は2つ、/usr/local/lib/prince/style/fonts.cssを弄るか、msttcorefontsをインストールするか
私はmsttcorefontsをインストールすることにした。
まずはrepoを新規作成

$ sudo vi /etc/yum.repos.d/puias-unsupported.repo
[puias-unsupported]
name=PUIAS Unsupported
baseurl=http://elders.princeton.edu/data/puias/unsupported/5/i386/
enabled=1
gpgcheck=0

早速yumしてみると

$ sudo yum install msttcorefonts
...
Requires: /usr/sbin/chkfontpath
...

と怒れる。取り敢えずまたyumしてみると

$ sudo yum install chkfontpath
...
No package chkfontpath available.
...

またダメか!ググッてたら、chkfontpath Install Howto
ここが書いてありました!
まずatrpms-repoのrpmをダウンロード、ここ。64bitだからatrpms-repo-6-4.el6.x86_64.rpm←これ

$ wget http://dl.atrpms.net/el6-x86_64/atrpms/stable/atrpms-repo-6-4.el6.x86_64.rpm
$ sudo rpm -Uvh atrpms-repo*rpm
...

$ sudo yum install chkfontpath
...
Complete!

成功!最後はfontだ

$ sudo yum install msttcorefonts
...
Complete!

やったー!もう一回princeを実行してみる

$ /usr/local/bin/prince --input=html --server -s /home/kagen/work/anyproj/public/stylesheets/application.css -s /home/kagen/work/anyproj/public/stylesheets/print.css -s /home/kagen/work/anyproj/public/stylesheets/prince.css ~/test.html -o test.pdf
...
sta|Converting document...
prg|0
prg|100
fin|success

できた…
以上。

2011年12月20日火曜日

CentOS6(64bit)にHTML+CSSをPDFに変換するprince8

railsのプロジェクトでHTML+CSSをPDFに変換する必要がありました。
ApacheのFOPがありました。無料ですが、それはHTMLとCSSではなくXSL-FO(XML)からPDFに変更するというものでした。しかもいろいろできないことが有るみたい(文字を画像の回り込みなど)。
さらに調べたら、princeがあって、HTML+CSSをPDFに変換できる。特徴はいろいろ、かなりイケてる感じ
1.各プラットフォームに対応http://www.princexml.com/download/
2.PDFファイルの出力は当然ですが、標準出力も対応
3.テーブルの中でページが割れないように設定できる
4.ヘッダー、フッター、ページナーンバー
5.大きくしてもボヤけないSVGの読み込みが対応
6.いろんな言語のWrappersがある(Java/Python/Perl/PHP/VB....)⇒rubyがない…でも大丈夫みたい
取り敢えずインストールしてみる

$ cat /etc/redhat-release
CentOS Linux release 6.0 (Final)
$ uname -a
Linux localhost.localdomain 2.6.32-71.el6.x86_64 #1 SMP Fri May 20 03:51:51 BST 2011 x86_64 x86_64 x86_64 GNU/Linux

OSはCentOS6(64bit)みたい。
ここからダウンロード
RHEL5: CentOS 5.5 / 64-bit
prince-8.0-1.centos55.x86_64.rpm

$ cd ~/download
$ wget http://www.princexml.com/download/prince-8.0-1.centos55.x86_64.rpm

普通にインストールしたら怒られた、openssl64bitはちゃんとあるのに

$ sudo rpm -ivh prince-8.0-1.centos55.x86_64.rpm
エラー: 依存性の欠如:
libcrypto.so.6()(64bit) は prince-8.0-1.x86_64 に必要とされています
libcurl.so.3()(64bit) は prince-8.0-1.x86_64 に必要とされています
libexpat.so.0()(64bit) は prince-8.0-1.x86_64 に必要とされています
libfontconfig.so.1()(64bit) は prince-8.0-1.x86_64 に必要とされています
libfreetype.so.6()(64bit) は prince-8.0-1.x86_64 に必要とされています
libgif.so.4()(64bit) は prince-8.0-1.x86_64 に必要とされています
libjpeg.so.62()(64bit) は prince-8.0-1.x86_64 に必要とされています
libpng12.so.0()(64bit) は prince-8.0-1.x86_64 に必要とされています
libpng12.so.0(PNG12_0)(64bit) は prince-8.0-1.x86_64 に必要とされていま す
libssl.so.6()(64bit) は prince-8.0-1.x86_64 に必要とされています
libtiff.so.3()(64bit) は prince-8.0-1.x86_64 に必要とされています
libungif.so.4()(64bit) は prince-8.0-1.x86_64 に必要とされています
[kagen@localhost download]$ rpm -qa | grep openssl-devel
openssl-devel-1.0.0-4.el6_0.2.x86_64

検索したら、ここにたどり着いた。同じ困っている人がいた。http://www.princexml.com/bb/viewtopic.php?f=2&t=7021
8.1から対応してくれそうです。

$ wget http://www.princexml.com/download/prince-8.0-linux-amd64-static.tar.gz
....
$ tar xzvf prince-8.0-linux-amd64-static.tar.gz
....
$ cd prince-8.0-linux-amd64-static
$ sudo ./install.sh
[sudo] password:
Prince 8.0

Install directory
This is the directory in which Prince 8.0 will be installed.
Press Enter to accept the default directory or enter an alternative.
[/usr/local]:⇒ブランクのままエンター

Installing Prince 8.0...
Creating directories...
Installing files...

Installation complete.
Thank you for choosing Prince 8.0, we hope you find it useful.
Please visit http://www.princexml.com for updates and development news.
$ prince --version
Prince 8.0
Copyright 2002-2011 YesLogic Pty. Ltd.
Non-commercial License

取り敢えずインストール出来たみたい。

2011年12月13日火曜日

新しい作ったサーバになんとsshとscpコマンドがない。

bash: scp: コマンドが見つかりません
bash: ssh: コマンドが見つかりません

sshdなどは入っているけど、なんで?
まぁインストールします。

# sudo yum install openssh-clients
...
# which ssh
/usr/bin/ssh

インストールされた。

2011年12月2日金曜日

COUNTIF,SUMIF,SUMPRODUCT

よく使うのはCOUNTIF,SUMIF
複数条件時は、SUMPRODUCTだと便利です。

商品名 クラス 販売数量 単価
リンゴ A 3 200
リンゴ S 2 600
バナナ A 5 90
B 7 100
リンゴ B 12 50

求め 数式 結果
単価が100円以上の商品数 =COUNTIF(D2:D6,">=100") 3
リンゴの販売数は =SUMIF(A2:A6,"=リンゴ",C2:C6) 17
リンゴの売上は =SUMPRODUCT((A2:A6="リンゴ")*C2:C6*D2:D6) 2400
リンゴクラスAとAAの総売上は =SUMPRODUCT((A2:A6="リンゴ")*((B2:B6="A")+(B2:B6="S"))*C2:C6*D2:D6) 1800

Excelの#DIV/0!エラー

Excel2007では通常はこれで隠すが
IFERROR(A1/A2,"")

Excel2000では(2003は確認していません)"IFERROR"がないので
IF(ISERROR(A1/A2),"",A1/A2)
で代替できる