uzullaの日記

本家:about等:Twitter

2008-05-22

redhat 7.1にRuby1.8.6を入れる

| 12:58

お客さんにある老体サーバーRails環境をつくってくれ、といわれたので作っている。

RH7.1が許されるのは5年前までだよねー(アハハー)


まず普通に落としてきてビルドしたけど、動かなかった。

makeに失敗する、そんなシンボル定義されていないとか出るので、どうやらOpenSSLのライブラリが古すぎるらしい。

Rubyは0.9.7以降のOpensslライブラリを要求するらしい。


手として、OpenSSLのバージョンを上げるか、または

ext/openssl

のコードを削除してしまう。


OpenSSLのバージョンを上げる

0.9.8の最新版を落としてきてBuildしたが、ビルドが通らなかった。

どうもアセンブラコードのコンパイルに失敗している。

no-asmオプションをつけたら動いた。

config no-asm shared

make all

make install

または0.9.7系であればno-asmせずビルドが通る模様。

shared オプションは多分必要(libssl.so.0.9.7等が作られない)

後、/etc/ld.so.confに/usr/local/ssl/libを追記しておいたほうがイイと思う。


Rubyを改めてビルドする

./configure --with-openssl-dir=/usr/local/ssl

make all

make install


うごいた

[root@sv /etc]# cat redhat-release

Red Hat Linux release 7.1 (max-R4.1.1)

[root@sv /etc]# ruby -v

ruby 1.8.6 (2008-03-03 patchlevel 114) [i686-linux]

pdmrfvtpdmrfvt2011/04/06 17:1862HQ06 <a href="http://dftuheoxevnd.com/">dftuheoxevnd</a>, [url=http://plttmttjzfbi.com/]plttmttjzfbi[/url], [link=http://ugsmipiqivcg.com/]ugsmipiqivcg[/link], http://dbtuwfkuadxi.com/

2008-03-19

おまけ、Rubyで文字をエンコードしたり、デコードしたり

| 15:32

今回各社の資料に載っていたUnicodeの0xFFFFの16進数形式を10進数に変換する為にRubyの書き方を覚えました。

(なんで16進数のままやらなかったかって?10進数のほうが解りやすかったから…)


文字を数値にエンコードしたりデコードするには "A".unpack('U')[0] とします。

最後の[0]は、"A".unpack('U')は配列を返すので中身を返しているだけです。

これは一文字だけなので、複数文字をやるときは

"abcdefg".unpack('U*').join('')

とやります、*は入力全てに対して処理するという意味です(指定しないとPackテンプレートの1単位しか処理されない)


要は、バイト列をunpackするとは、バイト列(というかString)をpackテンプレート引数にそった形式できりはなし(*の場合)、配列に詰めていきます。

unpack()と対になるpack()は、配列それぞれを1要素(Packテンプレートで指定された要素)であると判断して、エンコードします。

Packテンプレートの一覧はこちら、色々あって面白い。

http://www.ruby-lang.org/ja/man/html/pack_A5C6A5F3A5D7A5ECA1BCA5C8CAB8BBFACEF3.html


良くある例、URLエンコード

Perlで何度も書くURLエンコード変換について書くと

a=""

"あいうえお".each_byte {|c| a += sprintf("%%%x", c)}

p a

または

p "あいうえお".unpack('H*').join('').gsub(/[0-9a-f]{2}/, '%\&')

と、すっきり書けます、見やすくていいですね。


逆にデコードだと

chars = []

"%61%62%63".gsub(/%([0-9a-f]{2})/){ chars << $1.hex }

p chars.pack("U*")

とか書くのか?定石がわからん、デコードはちょっとめんどいか(上のはUNICODE考えてません)。

うーんPerlとまったく同じ書き方するの?


まあ、そんなことしなくても

標準ライブラリCGIをつかえば

require "cgi"

p CGI.escape('あいうえお')

p CGI.unescape('%40%23%23')

とかやるだけなんですけどね。

KeyaanKeyaan2012/01/06 15:51A ltilte rationality lifts the quality of the debate here. Thanks for contributing!

2008-03-05

上の問題を回避するactionを書いて^H^H^Hパクってみた。

| 23:47

参考になるコードを見つけたので、

(こちら、au用 > http://yoshimeux.seesaa.net/article/60916058.html

それを元にDocomo版を書いてみた。とりあえず手持ちのF904iで動作することは確認した。

  def get3gp
    # WEBrickがHTTP_RENGEリクエストがバグってる?ので回避する為のアクション
    # 参考URL(というかパクり元) http://yoshimeux.seesaa.net/article/60916058.html
    # Windowsで実行したらIO::readがうまく動かなかったので修正
    # iMotion(Docomo)ではLast-Modified も必要らしいので、修正
    # ezモーション(au)ではテストしてません
    
    path = $STOREDIR + params[:filename].to_s + '.3gp' # ファイルへの実パス
    filesize = File::size(path)

    range = request.env["HTTP_RANGE"]
    if range and /^bytes=(\d+)\-(\d+)$/ =~ range
      offset = $1.to_i
      limit = $2.to_i
      length = limit - offset + 1
      puts offset,':',limit,':',length
      response.headers["Content-Range"] = sprintf("bytes %d-%d/%d", offset, limit, filesize)
      response.headers["Content-Disposition"] = "devmpzz" #Docomoにはいらない筈…多分、トマソン      
      file = open(path)
      file.binmode
      file.seek(offset)
      content = file.read length 
      status = 206
    else
      file = open(path)
      file.binmode
      content = file.read filesize
      status = 200
    end
    
    if length.nil?
      length = filesize
    end
    response.headers["Accept-ranges"] = "bytes"
    response.headers["Content-Length"] = length.to_s
    response.headers["Last-Modified"] = "Wed, 21 Jun 2006 00:00:00 GMT" #適当実装FIXME
    response.headers["Content-Transfer-Encoding"] = "binary"

    #puts "filelength" + content.size.to_s
    #puts response.headers.inspect
    render :text => content, :status => status, :content_type => "video/3gpp", :layout => false
  end

とりあえずこれでしばらくしのごう…。


rails

/test/hogehoge.3gp

ってリクエスト投げると、ドット以降を別に取ってしまうので、不便かも。

/test/hogehoge%2e3gp

とかふざけた逃げをすればいいのかもしれないが。

2008-02-27

IO.popen(cmd_string, "r+") { |io| block } 便利だな

| 16:34

Perlとか使ってると、しばしば

open(NKF, ' | nkf | ');
print NKF $before;
$after = <NKF>;

みたいなことをしたくなると思う、俺だけかもしんないけど。

でも知っての通りこれはできない。


Rubyだと

    @source = '入力テキストです'
    cmd_string = [$MECAB_PATH, option].join(" ")
    @output = Array.new
    IO.popen(cmd_string, "r+") { |io|
      io.puts @source
      io.each{ |line|
        @output.push( line ) 
        if line =~ /EOS/ then
          break
        end
      }
    }

とかできるので便利すぎる。


まあ、Perlでもやろうと思えばできるんだけど

クックブックとかにもやり方は載っているのだけれど「デッドロックするからやめれ」という事ですね。

上のはMecabを呼び出すんですけど、まだプロトタイプなのでさっさと書きたかった、Windows環境だし。

最終的にはMeCabRubyバインディングを使う予定。


マルコフ連鎖

| 18:56

ある仕事でマルコフ連鎖のサンプルアプリが必要になったので、作ってみた。

railsのcontrollerから適当に抜粋、見て解るだろうけど、text actionがmain的。

(後日談、ヒドイバグがあったので修正)

(追記、出力が偏りがちだったり、短くなってしまうので、ランダムに1連鎖を利用して新しい風を吹き込む)

  def keychoice(target) #targetはhash
    # ハッシュ(target)のキー群の中からの一つのキーStringをランダムに返す     
    puts target.keys.to_s + ">" + target.keys[ rand( target.size ) ].to_s
    return target.keys[ rand( target.size ) ].to_s
  end
  
  def text
    @source = ( params[:text].nil? ? '' : params[:text] )
    if @source.size > 0 then # 入力が空なら処理しない
      
      #-------------------------------------------------------------------------
      # 入力文字列のゴミ掃除
      # 
      @source.gsub!(/\r/, "\n")
      @source.gsub!(/\n/, "")
      @source.gsub!(/[ ]+/, " ")
      #ゴミとかもうちょっと取り除いた方がいい、・。、などの連打とか FIXME


      
      #-------------------------------------------------------------------------
      # 分かち書き処理
      #
      @tokens = Array.new # @tokens 分かち書きした要素が入る配列
      # Mecabを起動して、@sourceを入力する
      # 出力(一行)を取得する
      # デッドロック注意
      # $MECAB_PATHはめかぶへのPath
      option = '-O wakati'
      cmd_string = [$MECAB_PATH, option].join(" ")
      IO.popen(cmd_string, "r+") { |io|
        io.puts @source
        @tokens = io.gets.split(/ /)
      }
      
      # @wakati_text 分かち書きされたテキスト、サンプル出力用
      @wakati_text = @tokens.join("\n")
      
      #-------------------------------------------------------------------------
      # 二連のマルコフ連鎖配列を生成 
      # 

      @markov = Hash.new # @markov マルコフ連鎖配列を格納する

      #マルコフ連鎖用の配列について簡単な解説。
      # 私,は,名前,は,田中,で,す 
      #という@tokensが入力されたとすると(説明の為に日本語は適当、
      #hash[私][は][名前]
      #hash[は][名前][は]
      #hash[名前][は][田中]
      #hash[は][田中][で]
      #hash[田中][で][す]
      #という二次元Hash @markovが作成される。
      #当然だが、hash[は]には[名前]と[田中]というキーのHashが格納されている
      #これが人工無能的出力を作る時には、重要になる
      #これは二連のサンプルであり、この深さをふやせば三連になる
      #三連にすると自然になるらしい、試す FIXME

      if @tokens.size > 3 then # 2連のマルコフ連鎖を作成するので、トークンが3つ以下だと処理できません        
        for i in 2..@tokens.size #2から始まる理由は前述の解説参照
          if i < @tokens.size then
            if @markov[@tokens[i-2]] == nil then 
              @markov[@tokens[i-2]] = Hash.new
            end
            @markov[@tokens[i-2]][@tokens[i-1]] = Hash.new 
            @markov[@tokens[i-2]][@tokens[i-1]][@tokens[i]] = '' #値はダミー
            #puts "'#{@tokens[i-2]}' '#{@tokens[i-1]}'"
            #puts @markov[@tokens[i-2]][@tokens[i-1]]
          end
        end
        
        
        #-------------------------------------------------------------------------
        # マルコフ連鎖配列を利用して、人工無能的文章の生成
        #
        
        pre1 = @tokens[0] # 開始の単語を選ぶ、入力文章の先頭は先頭にふさわしい単語だろう、
                          # という予測に基づく、将来的にはランダムに? FIXME
        pre2 = keychoice( @markov[pre1] ) # hash[HOGE][?] 存在する?群からランダムに取得
        suf1 = keychoice( @markov[pre1][pre2] ) 
        
        @output = pre1 + pre2 + suf1 # @output 最終的に生成される文字列
        
        for i in 1..1000 # この数に根拠なし、whileにすべきでは?

          if 1 == rand(2) then # たまーに新しい風を吹き込む
            pre1 = suf1
            if @markov[pre1].nil?
              break
            end
            pre2 = keychoice( @markov[pre1] )
            if @markov[pre1][pre2].nil?
              break
            end
            suf1 = keychoice( @markov[pre1][pre2] ) 
            @output += pre2 + suf1
          end

          pre1 = pre2
          pre2 = suf1
          if @markov[pre1][pre2].nil? then
            break
          end
          suf1 = keychoice( @markov[pre1][pre2] )
          @output += suf1;

        end
        
        @output
      else 
        @output = "文章が短すぎてマルコフ連鎖が行えません。";
      end
    end
      
    respond_to do |format|
      format.html 
    end
  end

別に1から自分で書いた訳ではなく、こちらのサイトのまるパクりです。

(追記:ちまちま修正更新したので、まるパクリから2/3パクリくらいになりましたw)

http://shohoji.net/blog/archives/000627.html

Rubyで書いてあるサイトがみつからなかったので。


見て解りますが、別途Mecabが必要です。

2008-02-22

Rubyからffmpegを叩くライブラリ

| 23:00

動画ファイルを入力して、色々な形式に変換する機能を作っている。

メールで写ムービーを送信したら作成されるとかも作る予定。

class FfmpegWrapper
  # 各機種用のProfile
  @@profiles = {
    
    # Docomo 3gp High 
    'docomo_high.3gp' => { 
      :f       => '3gp', #file suffix
      :vcodec  => 'mpeg4', # codec
      :s       => '320x240', # resolution
      :r       => 15, # frame rate
      :b       => '128k', # video bit rate
      :acodec  => 'libamr_nb', # audio codec
      :ab      => '4.75k', # audio bit rate
    },
    
    # Au 3g2 High 
    'au_high.3g2' => { 
      :f       => '3g2', #file suffix
      :vcodec  => 'mpeg4', # codec
      :s       => '320x240', # resolution
      :r       => 15, # frame rate
      :b       => '80k', # video bit rate
      :acodec  => 'libamr_nb', # audio codec
      :ab      => '4.75k', # audio bit rate
    },
    
    # PC flv High 
    'pc_high.flv' => { 
      :f       => 'flv', #file suffix
      :vcodec  => 'flv', # codec
      :s       => '320x240', # resolution
      :r       => 30, # frame rate
      :b       => '384k', # video bit rate
      :acodec  => 'libmp3lame', # audio codec
      :ar      => '11025',
      :ab      => '32k', # audio bit rate
    },
    #適当に追記する
    
  }
  
  def initialize()
  end
  
  def setandgo(setting)
    set(setting)
    run()
  end
  
  #パラメータ設定
  def set( setting )
    #setting{ :ffmpeg  => '/path/to/ffmpeg', 
    #         :ifile   => '/path/to/inputfile',
    #         :ofile   => 'outputfile', 
    #         :profile => 'targetName', }

    @ffmpegOptions = Array.new
    @@profiles[ setting[:target] ].each{ |k,v|
      @ffmpegOptions.push(%Q{ -#{k} #{v}})
    }
    
    @cmd = Array.new
    @cmd.push %Q{#{setting[:ffmpeg]} -i "#{setting[:ifile]}" #{@ffmpegOptions} "#{setting[:ofile]}" }
  end
  
  # @cmdを実際に実行
  #エラー処理などを全く行っていない。 FIXME
  def run()
    stdout = ""
    io = IO.popen("#{@cmd}", "r");
    io.each("\n") {|line|
      stdout << line
    }
    io.close
    return stdout
  end

  # 登録プロファイルのKeyリストを返す
  def profiles()
    rtnarr = Array.new()
    @@profiles.each{ |k,v|
      rtnarr.push(k)
    }
    return rtnarr
  end
  
end


#以下利用例
#1ファイルから全てのプロファイルへ変換
ffmpeg =  FfmpegWrapper.new()
targets = ffmpeg.profiles()
      
setting = Hash.new
setting[:ffmpeg] = 'c:/bin/ffmpeg/bin/ffmpeg.exe'
setting[:ifile] = 'c:/tmp/' + 'testfile.3gp' #入力ファイル
     
targets.each{ |target|
  setting[:ofile] = 'c:/tmp/' + 'testfile.3gp' + "_" + target #出力ファイル名
  setting[:target] = target
  ffmpeg.setandgo( setting )
}

どうでもいいけど、Rubyハッシュなどの記述で最後に,があってもエラーにならないから楽でいいね(コピペ的な意味で)