Hatena::Diary

しょんぼり技術メモ

2010-06-23 一万億兆京垓𥝱穣溝澗正載極恒河沙阿僧祇那由他不可思議

億とか京とか

| 22:25 | 億とか京とか - しょんぼり技術メモ を含むブックマーク はてなブックマーク - 億とか京とか - しょんぼり技術メモ

Ruby-listのMLで流れていた、[ruby-list:47175] 金額を漢字フォーマット 億, 千, 万を見て、汎用的に「n桁で区切っていく接頭辞系」を作れないかなと思って試しにやってみた。

#!/usr/bin/ruby -Ku
# -*- coding: utf-8 -*-

Units = [ ""  , "", "", "", "",
          "", "禾予", "", "", "",
          "", "", "", "恒河沙", "阿僧祇",
          "那由他", "不可思議", "無量大数"]
Digit_per_unit = 4

def to_jp_unit(num)
  str = num.to_s
  r_ary = str.split(//).reverse

  result_ary = Array.new
  buf = Array.new
  is_empty = true # zero skip flag

  r_ary.each do |digit|
    buf.unshift(digit)

    is_empty &&= (digit == "0")

    if buf.length >= Digit_per_unit
      if is_empty
        result_ary.unshift("")
      else
        result_ary.unshift("#{buf}#{Units[result_ary.length]}")
      end
      buf.clear
      is_empty = true
    end
  end

  if buf.length > 0
    result_ary.unshift("#{buf}#{Units[result_ary.length]}")
  end

  result_str = ""
  result_ary.each{|part| result_str += part }
  return result_str
end


while(line=gets) do
  num = line.to_i
  puts "#{num} -> #{to_jp_unit(num)}"
end

'Digit_per_unit'で区切る桁数を、Unitsに接頭辞を列挙。Digit_per_unitを3にして、Unitsに"K,M,G,T,P,..."とやれば、SI接頭辞に。

…3(SI接頭辞)と4(命数法)しか思いつかないけど。

実際に万億兆...とやりたい場合は、↑のURLでやってる方法が早いんじゃないかと思います。思いついたままにコーディングしてるので、逆順配列作ったり作業用配列作ったりしてるので遅いはず。


追記

投稿してから気づいたけど、こうすりゃもっとシンプルでした。


def to_jp_unit2(num)
  num_str = num.to_s
  target_digits = num_str.split(//).length
  unit_count    = (target_digits / Digit_per_unit).to_i
  unit_count.downto(0) do |i|
    regexp_str = "([1-9]\\d{0,3})(\\d{#{i*Digit_per_unit}})$"
    replace_to = "\\1#{Units[i]}\\2"
    num_str.sub!(Regexp.new(regexp_str), replace_to)
  end
  num_str.gsub!(/(\D)0+/, '\1')
  return num_str
end

2010-06-13 それシェルでできるよ

あるディレクトリにある全てのファイルの内容を置換する

| 00:29 | あるディレクトリにある全てのファイルの内容を置換する - しょんぼり技術メモ を含むブックマーク はてなブックマーク - あるディレクトリにある全てのファイルの内容を置換する - しょんぼり技術メモ

d:id:d-kami:20100613を見て、それ別にRuby使わなくてもシェルで、しかも一行でできるよ、と思ったので書いておく。

原理はカンタン、対象となるファイルをfindでリストアップして、xargsで他のコマンドに渡すだけ。

sedコマンドは、"-i"オプションでファイルに対して破壊的な変更を行うことができる。なので、一度別のファイルにはき出して元のファイルを削除してリネーム、なんてことも必要ない。

$ find . -name '対象ファイルパターン' -print0 | xargs -0 sed -i '置換正規表現'

具体的には、こんな感じ。

$ cat dir1/hello.txt
hello d_kami!
bye, d_kami!

$ cat third_dir/haro-.txt
haro- d_kami!
baibai d_kami...

$ find . -name '*.txt' -print0 | xargs -0 sed -i 's/d_kami/yas/g'

$ cat dir1/hello.txt
hello yas!
bye, yas!

$ cat third_dir/haro-.txt
haro- yas!
baibai yas...

やはり、yaslinuxの基本コマンド群は偉大である。

2010-06-10 今日もRubyちゃんとちゅっちゅ

IPアドレスを扱う

| 17:41 |  IPアドレスを扱う - しょんぼり技術メモ を含むブックマーク はてなブックマーク -  IPアドレスを扱う - しょんぼり技術メモ

IPアドレス・サブネット関係の処理が必要になったので調べた。

"IPAddr"クラスを使うようだ。そのメモ。

参照:ipaddr - Rubyリファレンスマニュアル

irb(main):001:0> require 'pp'
=> true
irb(main):002:0> require 'ipaddr'
=> true

irb(main):003:0> ipaddr1 = IPAddr.new("192.168.0.3")
=> #<IPAddr: IPv4:192.168.0.3/255.255.255.255>
irb(main):004:0> ipaddr2 = IPAddr.new("192.168.0.103")
=> #<IPAddr: IPv4:192.168.0.103/255.255.255.255>
# 素直に文字列としてIPアドレスを渡してやればOK


irb(main):005:0> ipaddr1 == ipaddr2
=> false
# 単純な比較


irb(main):006:0> masked = ipaddr1.mask("255.255.255.0")
=> #<IPAddr: IPv4:192.168.0.0/255.255.255.0>
# 既存のオブジェクトに、指定したネットマスクを適用したオブジェクトを取得


irb(main):007:0> masked.include?(ipaddr1)
=> true
irb(main):008:0> masked.include?(ipaddr2)
=> true
irb(main):009:0> ipaddr3 = IPAddr.new("192.168.1.3")
=> #<IPAddr: IPv4:192.168.1.3/255.255.255.255>
irb(main):010:0> masked.include?(ipaddr3)
=> false
# ネットマスク付きオブジェクトに含まれるかどうかをinclude?で取得


# ネットマスク付きオブジェクトを作るときは、↓こうじゃなくて
irb(main):011:0> range = IPAddr.new("172.16.0.5","255.255.0.0")
ArgumentError: address family unmatch
        from /usr/lib/ruby/1.8/ipaddr.rb:436:in `initialize'
        from (irb):11:in `new'
        from (irb):11

# ↓こうする。aaa.bbb.ccc.ddd/www.xxx.yyy.zzz 形式か、aaa.bbb.ccc.ddd/xx 形式を使う。
irb(main):012:0> range = IPAddr.new("172.16.0.5/255.255.0.0")
=> #<IPAddr: IPv4:172.16.0.0/255.255.0.0>

irb(main):013:0> ipaddr4 = IPAddr.new("172.16.100.200")
=> #<IPAddr: IPv4:172.16.100.200/255.255.255.255>
irb(main):014:0> range.include?(ipaddr4)
=> true
irb(main):015:0> range.include?(ipaddr1)
=> false

2010-05-31 続・ぶいぶいぶいっ

V-Fieldを使ってみた

| 21:58 | V-Fieldを使ってみた - しょんぼり技術メモ を含むブックマーク はてなブックマーク - V-Fieldを使ってみた - しょんぼり技術メモ

りべんじ。

前回のエントリについて

前回(d:id:syonbori_tech:20100530)はコンパイルに成功したところまで。そこでいくつか修正を行ったが、それがあってるかどうか不安だったので、@に聞いてみた。

どうやら、"-static"はgccへの指定で、スタティックリンクライブラリを指定する物らしい。"-static -lboost_thread-mt" とした場合、libboost_thread-mt.aがリンクされるらしい。Fedora12でyumを使ってboostをインストールする場合、.soしかインストールされないため、エラーとなっていたようだ。

とりあえず、"-Bstatic"でも動いているが、念のため補足。


足りないパッケージをインストール

nbdが必要だった。さくっとインストーる。

# yum install nbd

V-FIELDを使ってみる

PC1とPC2の環境を用意して、PC1上にファイルを用意して、PC2から参照してみる。

PC1(最初に提供する側)

動作確認のため非デーモンモードで動作させる。

$ ./vfield -file /tmp/random_10MB -if eth0 -nodaemon
RootStorage is initialized with /tmp/random_10MB (10485760 bytes)
Stream is listened on aaa.bbb.ccc.ddd:19660
RPC is listened on any:19660
NBD is listened on 127.0.0.1:8990

どうやらRPCに19660/TCPを使うようだ。

PC2(見に行く側)

こちらも非デーモンモードで動作させる。vfieldを実行するターミナルと、nbd-clientでマウント?を行うターミナルの二つが必要。

$ ./vfield -bs aaa.bbb.ccc.ddd -store 1 -nodaemon
Storage layer is initialized with 1048576 bytes limit
Stream is listened on aaa.bbb.ccc.ddd:19660
RPC is listened on any:19660
NBD is listened on 127.0.0.1:8990
Stream Join succeeded, image size is 10485760 bytes
Storing data range is 7340032 - 8388607

"-store"で指定するのは、自分が保持する容量らしい。

そして、もう一枚のターミナルでnbd-clientを実行する。こちらにはroot権限が必要なようだ。

# nbd-client localhost 8990 /dev/nbd0
Negotiation: ..size = 10240KB
bs=1024, sz=10240

これで、/dev/nbd0 にPC1のファイルがマウントされる。

vfield側には次のような表示がされていた。

Storing data is successfully downloaded
NBD negotiation successed

ためしにのぞいてみる。

# hexdump -C /dev/nbd0 | head -n 10
00000000  50 e4 50 d0 99 8f e3 35  1b 42 b8 e1 93 f8 5f 41  |P.P....5.B...._A|
00000010  83 0b 78 6d e0 de 61 39  71 3d 05 5e 04 32 d7 d2  |..xm..a9q=.^.2..|
00000020  38 af a4 04 0e 51 62 d5  7f 64 db b8 67 02 d6 11  |8....Qb..d..g...|
00000030  87 40 69 ef ac 81 ac 56  82 58 12 6f 3d 5c 71 a6  |.@i....V.X.o=\q.|
00000040  02 e7 4b d2 9d 76 f4 a2  f6 20 4c 76 22 c1 c2 43  |..K..v... Lv"..C|
00000050  e7 24 d2 2f 98 19 32 22  6f 59 ea a5 47 54 f6 4e  |.$./..2"oY..GT.N|
00000060  03 f5 60 20 a5 a7 a8 0d  96 fe 20 2a df 2b 91 25  |..` ...... *.+.%|
00000070  64 a2 6e 60 a9 88 ec 5f  30 2b af 88 03 84 37 d4  |d.n`..._0+....7.|
00000080  53 c6 0b 95 0e b8 b6 ab  9b 4b 91 a6 49 76 ab ab  |S........K..Iv..|
00000090  5f e8 56 6e 12 39 66 56  6c 56 98 2e cd 5b 26 60  |_.Vn.9fVlV...[&`|

PC1側のものと一致したことを確認。


性能

VirtualBox上のゲストでやってるのでアテになりません…(´・ω・`)

2010-05-30 ぶいぶいぶいっ

V-Fieldを使ってみたい

| 03:43 | V-Fieldを使ってみたい - しょんぼり技術メモ を含むブックマーク はてなブックマーク - V-Fieldを使ってみたい - しょんぼり技術メモ

読み取り専用の分散多重化共有ブロックデバイス、V-FIELD(V-FIELD - VIVER)を使ってみようとした。

環境

Fedora12, x86_64, V-FIELD changeset 69

下準備

レポジトリへのアクセスにmercurial、コンパイルにimake, boostが必要なのでインストーる。

# yum install mercurial imake boost boost-devel

レポジトリからソースコードを取得

$ mkdir /usr/src/vfield
$ cd /usr/src/vfield
$ hg clone http://viver.sourceforge.jp/cgi-bin/repos/vfield.cgi
destination directory: vfield.cgi
requesting all changes
adding changesets
adding manifests
adding file changes
added 70 changesets with 815 changes to 121 files
updating to branch default
68 files updated, 0 files merged, 0 files removed, 0 files unresolved

vfield.cgiディレクトリ以下にコピーされる。


boostの変更に追従

boost/thread.hppをincludeするのではなく、boost/thread/condition.hppをincludeする必要があるらしい。

影響のあるファイルは

$ grep -R 'boost::condition' *
common/locked_queue.h:  boost::condition m_cond;
common/rw_lock.h:       boost::condition m_final;
common/notify.h:        boost::condition cond;
common/threadpool.h:    boost::condition ring_cond;
search/engine.cc:       boost::condition m_condition;
stream/stream.cc:       boost::condition m_sweep_thread_cond;

この6ファイルらしい。これらにincludeを追加する。

また、boost_threadがマルチスレッド用にboost_thread-mtと名前が変わっているので、あわせてRules.mkも変更する。

次のパッチファイルを使って一括更新する。

diff -Nur --exclude=Makefile --exclude=Makefile.bak --exclude=.hg vfield.cgi/Rules.mk vfield.cgi.new/Rules.mk
--- vfield.cgi/Rules.mk 2010-05-31 00:06:30.888090400 +0900
+++ vfield.cgi.new/Rules.mk     2010-05-31 00:57:27.121144254 +0900
@@ -1,5 +1,5 @@
 CXX ?= c++
-OPTIMIZE = -O5 -mtune=pentium4
+OPTIMIZE =
 RELEASE = $(OPTIMIZE) -DNDEBUG
 QUIET   = $(OPTIMIZE) -DQUIET
 QUIET0  = $(OPTIMIZE) -DQUIET0
@@ -7,7 +7,7 @@
 #CFLAGS += -Wall -g -pipe -I$(build_dir) -I$(build_dir)/common -D_FILE_OFFSET_BITS=64 $(RELEASE)
 CFLAGS += -Wall -pipe -I$(build_dir) -I$(build_dir)/common -D_FILE_OFFSET_BITS=64 $(RELEASE)
 #LDFLAGS += -lpthread -Wl,-Bstatic -lboost_thread -Wl,-Bdynamic -lrt
-LDFLAGS += -static -lboost_thread -lpthread -lrt
+LDFLAGS += -Bstatic -lboost_thread-mt -lpthread -lrt


 .SUFFIXES: .cc .o .h .h.gch .exe
diff -Nur --exclude=Makefile --exclude=Makefile.bak --exclude=.hg vfield.cgi/common/locked_queue.h vfield.cgi.new/common/locked_queue.h
--- vfield.cgi/common/locked_queue.h    2010-05-31 00:06:30.903091653 +0900
+++ vfield.cgi.new/common/locked_queue.h        2010-05-31 00:05:51.113101332 +0900
@@ -5,6 +5,7 @@
 #include <queue>
 #include <boost/shared_ptr.hpp>
 #include <boost/thread.hpp>
+#include <boost/thread/condition.hpp>

 // XXX: 例外処理が無い

diff -Nur --exclude=Makefile --exclude=Makefile.bak --exclude=.hg vfield.cgi/common/notify.h vfield.cgi.new/common/notify.h
--- vfield.cgi/common/notify.h  2010-05-31 00:06:30.906093691 +0900
+++ vfield.cgi.new/common/notify.h      2010-05-31 00:05:44.132098662 +0900
@@ -4,6 +4,7 @@
 #include <boost/shared_ptr.hpp>
 #include <boost/optional.hpp>
 #include <boost/thread.hpp>
+#include <boost/thread/condition.hpp>
 //#include <boost/bind.hpp>
 //#include <functional>

diff -Nur --exclude=Makefile --exclude=Makefile.bak --exclude=.hg vfield.cgi/common/rw_lock.h vfield.cgi.new/common/rw_lock.h
--- vfield.cgi/common/rw_lock.h 2010-05-31 00:06:30.907093439 +0900
+++ vfield.cgi.new/common/rw_lock.h     2010-05-31 00:05:47.598124341 +0900
@@ -2,6 +2,7 @@
 #define VFIELD_RW_LOCK_H__

 #include <boost/thread.hpp>
+#include <boost/thread/condition.hpp>
 #include <boost/utility.hpp>

 namespace VFIELD {
diff -Nur --exclude=Makefile --exclude=Makefile.bak --exclude=.hg vfield.cgi/common/threadpool.h vfield.cgi.new/common/threadpool.h
--- vfield.cgi/common/threadpool.h      2010-05-31 00:06:30.909090980 +0900
+++ vfield.cgi.new/common/threadpool.h  2010-05-31 00:05:39.931339695 +0900
@@ -6,6 +6,7 @@
 #include <boost/ptr_container/ptr_vector.hpp>
 #include <boost/ptr_container/ptr_deque.hpp>
 #include <boost/thread.hpp>
+#include <boost/thread/condition.hpp>
 #include <boost/function.hpp>
 #include <boost/bind.hpp>      // 使う側で便利用

diff -Nur --exclude=Makefile --exclude=Makefile.bak --exclude=.hg vfield.cgi/search/engine.cc vfield.cgi.new/search/engine.cc
--- vfield.cgi/search/engine.cc 2010-05-31 00:06:30.931102485 +0900
+++ vfield.cgi.new/search/engine.cc     2010-05-31 00:05:34.131130781 +0900
@@ -16,6 +16,7 @@
 #include <functional>
 #include <boost/bind.hpp>
 #include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/thread/condition.hpp>

 namespace VFIELD {

diff -Nur --exclude=Makefile --exclude=Makefile.bak --exclude=.hg vfield.cgi/stream/stream.cc vfield.cgi.new/stream/stream.cc
--- vfield.cgi/stream/stream.cc 2010-05-31 00:06:30.942272674 +0900
+++ vfield.cgi.new/stream/stream.cc     2010-05-31 00:05:19.169104287 +0900
@@ -14,6 +14,7 @@
 #include <deque>
 #include <algorithm>
 #include <boost/thread.hpp>
+#include <boost/thread/condition.hpp>
 #include <boost/bind.hpp>
 #include <boost/shared_array.hpp>
 #include <boost/scoped_ptr.hpp>

こんなファイルを、vfield.cgi と同じディレクトリに、cond-boost_thread.patch として作成し、次のようにして適用する。

$ patch -p0 < cond-boost_thread.patch
patching file vfield.cgi/Rules.mk
patching file vfield.cgi/common/locked_queue.h
patching file vfield.cgi/common/notify.h
patching file vfield.cgi/common/rw_lock.h
patching file vfield.cgi/common/threadpool.h
patching file vfield.cgi/search/engine.cc
patching file vfield.cgi/stream/stream.cc

makeする

$ make depend

大量のwarningが出てもとりあえず気にしない。

$ make

が通れば(どうやら)OK。


予想以上に手間取ったので今日はここまで。。。