2012-01-20 [Groovy] docx renamer Word文書のファイル名を タイトル+最終更新日
多様なサブディレクトリに置かれたワード文書を、このスクリプトを起動した地点に移動させ、かつ
ファイル名を、
"元の名前_メタデータに書かれたタイトル名_最終更新日.docx"
に変更するスクリプトです。
この操作は、非可逆に、大量に操作するので、元の文書はバックアップを取って様子を確認してから使ってみてください。
// ワード文書名に、タイトルと変更日のメタタグを追加する。 // 変更例 : 文書13.docx --> 文書13-Groovyでお掃除-20120117.docx startDir = "." new File(startDir).eachFileRecurse { file -> if (file.isFile() && file.name.endsWith("docx")){ new AntBuilder().unzip(src: file, dest:'/OUTPUT') { patternset { include(name: '**/core.xml') } mapper(type: 'flatten') } println file docxcore = new groovy.util.XmlParser().parse("/OUTPUT/core.xml") title = docxcore.toString().replaceAll(/(.*title\[attributes\=\{\}; value=\[)([^\]]*)(\]\], \{http:\/\/purl.*)/) {m0,m1,m2,m3->m2 } title = title.tr(':/ ','___') modified = docxcore.toString().replaceAll(/(.*\}modified\[attributes\=\{\{http.*W3CDTF\}; .*value\=\[)(20[^\]]*)(Z\]\]\].*)/) {m0,m1,m2,m3->m2 } modified = modified.replaceAll(/(.*)(T..:..:..)/) {m0,m1,m2 -> m1} modified = modified.replaceAll(/(\d+)\-(\d+)\-(\d+)/) {m0,m1,m2,m3 -> m1+m2+m3 } targetName= file.name.replaceAll('\\.docx','') +'-'+ title +'-'+modified +'.docx' println file.name + " renamed to " + targetName file.renameTo(new File((targetName ))) } }
2011-12-16 [Groovy] 自分のPCにある写真をPicasa webに丸ごとアップ
自分のPCにあるjpg写真をサブディレクトリーの階層ごと丸ごとアップロードします。
G* Advent Calendar 2011 17日目のネタです。 #gadvent2011
特にGroovyの新技術を使うこともなく、あくまて日用の小道具として、目的志向でGroovyを活用したいと思います。
picasaのwebストレージも Google+に参加するとほぼ容量無制限となるので、
公開するかどうかは、後でアクセス権の設定の時に考えるとして自分のPCの写真を全てPicasaに保存します。
目的は洪水対策ですね、自分の家のPCが全壊してもアルバムは保全したいと思います。
前提として使うアプリケーションは Gladinet Cloud Desktopです。
これによりPicasa web サービスがドライブとしてPCにマウントして見ることができます。
Picasa webサービズがドライブとして見えているのだから、
ここに一気に xcopy か robocopy で一気にコピーできるかというと、Picasa web には制約があって、サブディレクトリーは一段までです。
例えば
という深いディレクリーにある画像ファイルはそのままでは送れません、それを
という風にディレクトリー名をひとつの長いものに変えて送る必要があります。
ここでは特にPicasaのWebサービスAPIとかは使っていなのでPicasa以外の似たようなサービスにも適用できると思います。
以下のスクリプトは、自分の持っているjpgをまるごと複製するので、動かす頻度がとても少ないのでハードコードしまくりです。
コピー先のPicasaディレクトリーは、ルートが z:/GooglePicasa という設定になっている前提です。
またこのスクリプト自体は、複製元の写真の配置してある場所のルートで起動します。
sleep で相当遅くなってますが、これは Gladinet のフリー版は、一日あたりの転送数に、制限がある為です
まったりPCをつけっぱなしにて動かすことが前提です。
多分Gladinet側の問題たと思いますが、何やら動作が不安定です。
量的にGladinetに負荷をかけすぎているのかもしれません。
def targetDrive="z:\\GooglePiasa\\" // Gladinet で設定したPicasa Webサービスのroot directory File.metaClass.copy = { String destName -> if(delegate.isFile()){ new File(destName).withOutputStream{ out -> out.write delegate.readBytes() } } } new File(".").eachFileRecurse { file -> if(file.isFile() && file.name.endsWith('.jpg')){ curName = file.getPath().replaceAll(/.\\(.*)/) {m0,m1 -> m1} newName = curName.reverse().replaceFirst("\\\\", "----").reverse() newName = newName.replaceAll("\\\\", "_") newName = newName.replaceAll("----", "\\\\") newFile = new File(URLDecoder.decode(newName, "UTF-8")) println "現行ファイル名: "+curName println "新規ファイル名: "+newName subDir = newName.toString().replaceAll(/\\.*$/,"") if (subDir && subDir.length() +2< newName.length() ) { targetDir = new File(targetDrive+subDir) if (!targetDir.exists()) { println "Subdir作成:" + targetDrive+subDir new File(targetDrive+subDir).mkdir(); //make folders Thread.sleep(1000*60) } } new File(curName).copy(targetDrive+newName) Thread.sleep(1000*60) } }
2011-02-20 [Groovy][Twitter] 固定ハッシュタグ複数定点観測用追跡器作りました
[Groovy][Twitter] 固定ハッシュタグ複数定点観測用追跡器作りました。
#devsumi とか、#jawsug とか、ずっと追跡し続けたい固定ハッシュタグは、いくつかあるものです。
自分のPDAデバイスそのものでハッシュタグを追跡すると、途中を見落とししたり、電池切れで追えなくなったりします。
このような問題があるため、できれば追跡そのものは自宅のマシンで無人で行い、その結果を随時PDAで閲覧する方式の
方が便利が良いと思います。また、デブサミのような大規模なセミナーだと複数のハッシュタグを追わないと追いつかないケースもあり、
準備:
TAGS.txt という、事前に追跡しておきたい、お好みのハッシュタグテーブルを作ります、1件1行です。
実は、登録する単語は、ハッシュタグである必要はなく、また日本語でもOKです。TwitterはStream APIで検索する場合は、ハッシュタグのみが可能です、逆に通常の検索の場合は、日本語でも何でも探せますが、その代わり、即時性がありません、スピードと多様性はトレードオフですが、ここでは、記録性を優先するので、通常の検索で追っています、従って5分から10分程度の遅延を伴います。
動かし方: TAGS.txt と同じディレクトリーで HashTagChaser.groovyを動かします。
すると#jggug.log といった名前のログファイルが作られます。
この結果をPDAでコンファレンス会場などで閲覧すればOKです。
で、この結果を外からどうやって見るかですが、簡単なことですが単にDropboxのディレクトリー内で動かすだけです。
巨人の肩の上に立つ訳です。
Groovyをインスコするのはイヤという人のために、独立したjar版も作っておきました。
また、Dropboxのアカウントをお持ちでない人は、よかったらこちらからアカウント取得してください。
招待ありでアカウントを作成すると、紹介者と招待された人の双方に、初期値の2Gに、プラスで250MB の容量追加が与えられます。招待者の私(nemo10)も250MBメリットがあります。
#jggug #javareading #devsumi アイマス
それぞれのタグ名に応じて #jggug.log とか #javareading.log などのログが時々進んでいきます。
実行コード HashTagChaser.groovy >|groovy| import static groovy.util.GroovyCollections.combinations import groovy.util.Eval import groovyx.gpars.GParsExecutorsPool // 検索単語エンコード String.metaClass.encodeIt = { -> return URLEncoder.encode(delegate,"UTF-8").replaceAll(/\.log/,'') } assert "ツイッター.log".encodeIt() == "%E3%83%84%E3%82%A4%E3%83%83%E3%82%BF%E3%83%BC" // 発言番号を取得 String.metaClass.getNum = { -> if (delegate ==~/.*tag.*search.*/) { //println "発言番号取得 " + delegate.replaceAll(/.*:([0-9]+)/, '$1') return delegate.replaceAll(/.*:([0-9]+)/, '$1') } else { return delegate } } assert "tag:search.twitter.com,2005:16060673193".getNum() == "16060673193" // 発言IDを取得 String.metaClass.getID = { -> if (delegate ==~/.*\(.*\)/) { //println "ID取得 " + delegate.replaceAll(/([^ ]+) \(.*/, '$1') return delegate.replaceAll(/([^ ]+) \(.*/, '$1') } else { return delegate } } assert "nemo_kaz (kazuo nemoto)".getID() == "nemo_kaz" // 日本語チェック String.metaClass.isKana = { -> if (delegate ==~/.*[あ-んア-ン].*/) { return "OK" } else { return "NG" } } assert "tag:search.twitter.com,2005:16060673193".getNum() == "16060673193" ////////////////////////////////////// def loggers=[] def file = new File("TAGS.txt") file.eachLine{logname -> loggers.add (new Agent(logname+".log")) } for (;;){ try { loggers.each {clazz -> clazz.logIt() } Thread.sleep(1000*60*8) } catch (Exception e) { println "Exception"+e } } class Agent{ String url File fhandle def counter def logname Agent(String input) { logname=input fhandle = new File(input) //fhandle.write("aaa\n") } def logIt() { def feed = null print " " def atom2 = ("http://search.twitter.com/search.atom?q="+logname.encodeIt()).toURL().text feed = new XmlSlurper().parseText(atom2) feed.entry.collect{it}.reverse().each { if (counter < it.id.toString().getNum().toLong()) { counter = it.id.toString().getNum().toLong() if (it.title =~ /^RT/) {} else { println "■"+it.title +" "+it.author[0].name.toString().getID() fhandle.append("■"+it.title +" "+it.author[0].name.toString().getID()+"\n" ) } //RTは割愛 } else { Thread.sleep(1000*5) } }//each }//logIt() } //class Agent
2010-09-21 [Groovy] Twitterの特定キーワードを追跡し続けるスクリプト
TwitterのStream APIを使うと、簡単に特定ハッシュタグがリアルタイムに
追跡できるわけですが、その代わり、漢字をStream APIで追跡することはできません。
ハッシュタグが漢字であったり、ハッシュタグ以外も追跡したい場合は、通常の検索機能を使うと、追跡できますが、今度は逆にStreamではないので、動きが緩慢になります。
漢字は追えないとあきらめてしまえばかまいませんが、やはり汎用な物を持っておきたいので作っておきました。
即応性の要求される、2時間程度のコンファレンスの追跡はStream APIが良いわけですが、
複数日にわたるイベントの追跡は検索APIを使ってもかまわないといえます。
このような仕様なので使いどころがないと思っていましたが、ちょうどJavaOneが開催されていて、複数日ずーっとそれを追いたい訳なので、#javaonejp のハッシュタグで追跡し続けています。
記録性の為なのでテキスト出力の方が便利かなと思っています。
@Grab('net.homeip.yusuke:twitter4j:[2.0,)') import groovy.xml.Namespace // 発言番号を取得 String.metaClass.getNum = { -> if (delegate ==~/.*tag.*search.*/) { //println "発言番号取得 " + delegate.replaceAll(/.*:([0-9]+)/, '$1') return delegate.replaceAll(/.*:([0-9]+)/, '$1') } else { return delegate } } assert "tag:search.twitter.com,2005:16060673193".getNum() == "16060673193" // 発言IDを取得 String.metaClass.getID = { -> if (delegate ==~/.*\(.*\)/) { //println "ID取得 " + delegate.replaceAll(/([^ ]+) \(.*/, '$1') return delegate.replaceAll(/([^ ]+) \(.*/, '$1') } else { return delegate } } assert "nemo_kaz (kazuo nemoto)".getID() == "nemo_kaz" // 検索単語エンコード String.metaClass.encodeIt = { -> return URLEncoder.encode(delegate,"UTF-8") } assert "ツイッター".encodeIt() == "%E3%83%84%E3%82%A4%E3%83%83%E3%82%BF%E3%83%BC" // main if (args.length == 0) {println "検索単語を指定してください"; return } Long counter=1 for (;;){ def feed=null def atom2 = ("http://search.twitter.com/search.atom?q="+args[0].encodeIt()).toURL().text feed = new XmlSlurper().parseText(atom2) feed.entry.collect{it}.reverse().each { if (counter < it.id.toString().getNum().toLong()) { counter = it.id.toString().getNum().toLong() println "■"+it.title +" "+it.author[0].name.toString().getID() //println it.link[0] //println "class="+it.published[0].toString() } else { Thread.sleep(1000*90) } } }
動作イメージ
■スピーカーが来ない.... #javaonejp skrb
■[CodeGeneration] @Lazyをフィールドにつけると、初めてアクセスするときに初期化するようなアクセサを生成してくれる。 #javaonejp nobeans
■[CodeGeneration] @Lazyで展開される実装はdouble-checked-lockingっぽい。スレッドセーフか?というツッコミに、多分Yes、といってたけど、Java5以降はね、という条件が必要だと思った。 #javaonejp nobeans
■[CodeGeneration]後はアノテーションによるAST変換の例をいくつか紹介してから、DbCのGroovy実装であるGContractsの紹介。アノテーションにクロージャで事前条件と事後条件を指定すると実行前後でチェックする実装をAST変換で生成。 #javaonejp nobeans
■[CodeGeneration]次は、FindBugsのGroovy版的なCodeNarc。発見できるバグの種類は前者が200以上なのに対して、60いくつと少なめだけど、CodeNarcはAST変換でバグチェックを実現してるんだよ、と。 #javaonejp nobeans
■[CodeGeneration]Groovy標準付属のツールで、ASTツリーをGUI表示できる。その構造の見方の説明と、AST変換をするためのASTTransformationの実装の仕方の説明。 #javaonejp nobeans
■[CodeGeneratin]AST変換といっても文法的には万能じゃなくて、Groovyとして正しい文法でなければいけない。文法さえ正しければ、その意味は自由に書き換えられる。文法NGならSyntaxErrorが発生してAST変換まで到達しない。 #javaonejp nobeans
■そろそろModular&Jigsawが始まりそう。 #javaonejp nobeans
■@skrb ですよねー!だからこそ貴重な機会を大事にしたいです。 #javaonejp kawamnv
■セッションがはじまるまでウトウトしていた。いつのまにか部屋がいっぱいになっていた。このセッションもffull #javaonejp skrb
2010-08-15 [Groovy] ソースコード同士の類似性評価ツールを作ってみた
Q: あなたはテストエンジニアです、ここにテストしなくてはならないソースが大量にあります。
しかし、よくみるとコピペメソッドによる類似コードが多数あり、ロジックを共有してるコードが大量にあります。従って、全てのコードをテストする必要はなさそうです。
そこで、ここで類似コードに関しては、代表的ないくつかをテストするという抽出テストにしたいと思いました、ここで、どうやって選別しますか?
A:類似したコードを群として束ね、類似性の高いコードはテストを割愛します。
類似性検出方法は下記の手段を用います。
A B C D のコードがあった時。
ひとつめは
ふたつめは
- AとBのコードを足しあわせたファイルを作ります。 A+B
- 次にそれを圧縮します。 zip(A+B)
- そして、それをファイルサイズで割った値を算出します。 zip(A+B)/size(A+B)=f(AB)
ここで
f(AB)/f(AA)の値が1に近いとBはAとはあまり違わないものであるといえます。
もしも
f(AB)/f(AA)>1 の場合、1より大きい程、BはAとは異なったものであるといえます。
ここでzip()はrunlength方を使用していると想定しています。
runlength方は、ファイル内で同一パターンを見つけると、前出と同じ、といった表記に置換して圧縮する一般的な圧縮手法です。
動かし方
ソースコードの置いてあるディレクトリーの元の部分でこのスクリプトを動かすと、その下にある
実はすごく遅いです。当たり前、毎回圧縮しているのだから、ファイルIOをもっと減らしてマルチスレッドに
しないと実用的にはならない予感がします。
本来テスト対象コードが多すぎるから絞り込みたいという動機があるので、
処理速度がもっと速くないと使えないでしょう。
// ソースコード間の違いを評価するツール List codes=[] // ここでは 拡張子がjavaのコードを再帰的に収集します。 new File(".").eachFileRecurse { file -> if(file.isFile() && file.name.endsWith("java")) { name = file.getPath() //+file.getName() codes.add(file.getPath()) } } println "検査対象コード" println codes println "ソース間距離: (100より大きいほど、二つのファイルは異なっている。" num = 1 for (x in (0..codes.size-1)) { for (y in (0..codes.size-1)) { if (1 /* x!=y*/) { print "["+num++ +"]"+codes.getAt(y)+" "+codes.getAt(x)+"\t" isUnique(codes.getAt(x), codes.getAt(y)) } } } def isUnique(code1, code2) { File output0 = new File("doubled.txt") output0.write("") new File(code1).eachLine { line1 -> //println line1 output0.append(line1) } new File(code1).eachLine { line1 -> //println line1 output0.append(line1) } File output = new File("merged.txt") output.write("") new File(code1).eachLine { line1 -> //println line1 output.append(line1) } new File(code2).eachLine { line2 -> //println line2 output.append(line2) } proc = "cmd /c gzip -f doubled.txt".execute() proc.waitFor() proc = "cmd /c gzip -f merged.txt".execute() proc.waitFor() def zaa = new File("doubled.txt.gz").size() def zab = new File("merged.txt.gz").size() def a = new File(code1).size() def b = new File(code2).size() println " 類似性 ="+( (zab/(a+b))/(zaa/(a+a)))*100 }
実行イメージは例えば以下のようになります。
-------------------------------------------------------------------
[.\a.java, .\b.java, .\SOURCE1\a.java, .\SOURCE1\b.java]
ソース間距離: (100より大きいほど、二つのファイルは異なっている。
[1].\a.java .\a.java 類似性 =99.9551166900
[2].\b.java .\a.java 類似性 =37.2159692800
[3].\SOURCE1\a.java .\a.java 類似性 =192.5814740900
[4].\SOURCE1\b.java .\a.java 類似性 =103.5254833100
[5].\a.java .\b.java 類似性 =152.3449010600
[6].\b.java .\b.java 類似性 =99.9632623700
[7].\SOURCE1\a.java .\b.java 類似性 =178.8919630900
[8].\SOURCE1\b.java .\b.java 類似性 =279.0446589500
[9].\a.java .\SOURCE1\a.java 類似性 =27.5365924800
[10].\b.java .\SOURCE1\a.java 類似性 =6.2432073200
[11].\SOURCE1\a.java .\SOURCE1\a.java 類似性 =97.5609756100
[12].\SOURCE1\b.java .\SOURCE1\a.java 類似性 =12.7184763200
[13].\a.java .\SOURCE1\b.java 類似性 =133.4013067100
[14].\b.java .\SOURCE1\b.java 類似性 =87.9460498600
2010-05-22
■[Java][並行プログラミング]「並行プログラミングの原理から実践まで」5章の補助資料書きました。
「並行プログラミングの原理から実践まで」を社内勉強会で、輪読しています。
今回、第5章を担当しました。
解説資料のすべては下記URLから原板がダウンロードできます。
改変、再配布は自由とのこと。
Index of /acafinal/ACA Self Learn
わかりにくい部分に、日本語でコメントを追記して使用しました。
このパワーポイントの資料は、本より後から作られたものらしく、本とは構成が違っているので、併読すると、かえって混乱する可能性もあります。
jsr166y forkjoinを理解する前提として、java.util.concurrent をあらためて深掘りして理解しておく必要があると思います。
2010-05-04 [Groovy]ドライブ毎の空き容量を表示する。
その昔、DOSで動く FREE.COMというツールがありました。
各ドライブ事の残量を示してくれました。大きなファイルを書き出したりする前に
最も大きな空きスペースのドライブを確認するときなどに便利でした。
ファイル名は "FREE.COM" などと言う、おいしすぎる名前なので、
記憶していたイメージにもとづきGroovyで再開発してみました。
Windows専用になります。
(drive in "C".."Z") という拡張for文がちょっと便利ですね。
動作イメージ
drv [ 空き ]G [ 総計 ]G [Free]% C:\ [ 49.0]G [ 110.7]G [44.3]% D:\ [ 16.0]G [ 99.8]G [16.1]% Z:\ [ 0.3]G [ 0.3]G [100.0]%
println "drv [ free ]G [ total ]G [free]%" for (drive in "C".."Z") { file = new File("${drive}:/") BigDecimal free = file.getFreeSpace()/100000000 BigDecimal total= file.getTotalSpace()/100000000 if (total >0) { print file BigDecimal vaca = free/total*100 printf (" [%7.1f]G [%7.1f]G [%2.1f]",free,total,vaca) println "%" } }
2010-05-03 [Groovy]URLDecodeされなかったファイル名を直す。
Firefox pluginの Video DownloadHelperというツールがあります。
これは別に動画ダウンロード専用ではなく、拡張子を追加定義すれば ppt や doc や pdf も一気に落とすことが出来ます。
ただし日本語対応していないので、各種日本語名のファイルをダウンロードした時、ファイル名がURLDecodeされないままでファイルが落ちてきます。
例えば "ファイル名.pdf" というファイルは "%83%74%83%40%83%43%83%8B%96%BC.pdf"
という名前となってしまいます。
充分に日本語化対応していないツールでは、時々あることなので、この名前を元に戻すスクリプトを書きました。
開始ディレクトリーから下のファイル全てに対して、一気にファイル名のURLDecodeの書き戻しします。
new File(".").eachFileRecurse { file -> if(file.isFile()){ curName = file.getPath().replaceAll(/.\\(.*)/) {m0,m1 -> m1} newName = new File(URLDecoder.decode(curName, "UTF-8")) println "現行ファイル名: "+curName println "新規ファイル名: "+newName file.renameTo(newName) } }
2010-04-27 [Groovy]コマンドイラン電卓
2010-02-20 bit.lyでの圧縮をWeb APIでなく実行するGroovyスクリプト
tyamaさんの
bit.ly が普通におもしろかったのでGroovyでAPIを使って遊んでみた
http://d.hatena.ne.jp/mottsnite/20100209/1265725950
今まで適当にheaderのスクレイプでbit.ly圧縮していました。
APIがあるなら使うべきなので、そのうちこのメソッドはreplaceします。
ちなみに j.mp は単に bit.ly のエイリアスです。
headerの場合はloginとかなしでの実行となります。
今もこのメソッドでbot動かしています。
def getJmp(String longstr) { def url = 'http://bit.ly/?s=&keyword=&url='+URLEncoder.encode(longstr,"UTF-8") def ans = "" url.toURL().getText("UTF8").eachLine { if (it==~/.*\"shortUrl\".*\"(http.*)\".*/) { ans = it.replaceAll(/.*\"(http.*)\".*/) {m0, m1 -> m1 }.replaceAll(/bit\.ly/,"j.mp") } } return ans } assert getJmp('http%3A%2F%2Fwww-06.ibm.com%2Fsoftware%2Fjp%2F')== 'http://j.mp/cYbe1'
2009-12-06 Twitter Streaming API でTLをテキストでだらだら出力するGroovy
TwitterのTimeLineの出力をだらだらコンソールに出力するGroovyスクリプトです。
フォロワー数は200以下のアカウントでないと filterが動作しなくなります。
APIの制限です。
http://yusuke.homeip.net/twitter4j/ja/api-support.html#Streaming%20API%20Methods
の birddog filter() あたりの記述に制限も解説されています。
Pagingできるようなので、うまくやるとフォロアー数の制限を超えられるかもしれません。
そこは、まだ調べていません。
@Grab は、ついていますが、Groovyのバージョンで書式が変わるので、使わなくても良いと思います。
動作させると、塊ではなく、一件ずつ、だらだら "timestamp+id+本文" の書式でテキストで出力され続けます。
import twitter4j.http.* import twitter4j.* start() @Grab(group='net.homeip.yusuke', module='twitter4j', version='[2.0.10,)') def start() { def uid="ユーザーID" def pwd="パスワード" def twitter = new Twitter(uid, pwd ) def userIds = twitter.friendsIDs.IDs userIds.each {println " - " + it} println "Got friends userIds: ${userIds.size()}" def twitterStream = new TwitterStream(uid, pwd) twitterStream.statusListener = [ onException : { ex -> println ex}, onStatus : { status -> //status -> println status def time = status.toString().replaceAll(/.*createdAt.* ([0-9][0-9]:[0-9][0-9]:[0-9][0-9]) .*, id=.*/) {m0, m1 -> "${m1}" } def name = status.toString().replaceAll(/.*screenName='(.*)', location.*/) {m0, m1 -> "${m1}" } def text = status.toString().replaceAll(/.*text='([^']*)', source='.*/) {m0, m1 -> "${m1}" } println time+" "+name+"\t"+text } ] as StatusListener twitterStream.filter(0, userIds, [] as String[]) }
2009-08-29 GroovyでTwitter botを作るための code部品
あるTwitterアカウントでの最近の発言群の中心をなすキーワードを抽出したリストを作る。
または、収集ボットを作る時に、似たような投稿はふるい落とすことに使う。
それまでの投稿内容のキーワードを10単語まで、バッファに保存し続けて
今回収集した投稿文のキーワードが、いまあるバッファにある単語と一致したら、
同一トピックについて語った文面であると判定して、評価を下げます。
これによって、
例えばあるニュースが流れて、それに反応して多くの人がつぶやいたとします。
捕捉ボットは、その場合、一番最初につぶやいた人の文面は普通にキャッチしますが、
二番手以降のつぶやきの評価は、一番手の発言で使用された単語とかぶるので、
そのつぶやきの捕捉確率を下げます。
その後もつぶやきを捕捉し続けて、その単語がバッファ辞書から流れて消えていけば、またおなじ捕捉確率に戻ります。
キーワードの除外単語は
としました。
Yahoo APIのキーフレーズ抽出APIを使用しました。使用言語はGroovyです。
import twitter4j.* cache=["某0","某1","某2","某3","某4","某5","某6","某7","某8","某9"] Twitter twitter = new Twitter("ユーザーID","パスワード"); Iterator <Status> i= twitter.getUserTimeline("誰かターゲットのID").iterator(); while(i.hasNext()) { ans = i.next().getText() getKwd(ans) } def getKwd(String text) { parm1 = URLEncoder.encode(text.replaceAll(/#[^ ]+/,"").replaceAll(/@[^ ]+/,"") ,"UTF-8") // ハッシュタグとIDは除外 def rssFeed = ("http://jlp.yahooapis.jp/KeyphraseService/V1/extract?appid=取得したYahooAPIのID&sentence="+parm1).toURL().getText("UTF8") def rss = new XmlSlurper().parseText(rssFeed) kwd0= (rss.Result.Keyphrase[0]).toString().replaceAll(/ /,"") kwd1= (rss.Result.Keyphrase[1]).toString().replaceAll(/ /,"") if (kwd0 != "bit.ly"&& kwd0 != "tinyurl.com"&& kwd0 != "ff.im") { cache.add(kwd0) cache.remove(0) } if (kwd1 != "bit.ly"&& kwd1 != "tinyurl.com"&& kwd1 != "ff.im") { cache.add(kwd1) cache.remove(0) } // 短縮URLは除外 println cache }
ここではバッファ辞書サイズは10単語、ひとつの文から2単語ずつ抽出しています。
動作イメージ
[某2, 某3, 某4, 某5, 某6, 某7, 某8, 某9, 今多摩川, 花火] [某3, 某4, 某5, 某6, 某7, 某8, 某9, 今多摩川, 花火, 口語体] [某5, 某6, 某7, 某8, 某9, 今多摩川, 花火, 口語体, Gaelyk, Groovy] [某7, 某8, 某9, 今多摩川, 花火, 口語体, Gaelyk, Groovy, JConsole, JRuby] -- 以下続く --
ときどき対象外の単語があったときは、二つずつひろうとは限らなくなります。
2009-08-01 Google App Engine上でGroovyとTwitterを動かす為のセットアップガイ
Google App Engine上でTwitterをGroovyで動かす情報。
(bot作ろう会 Groovy分科会は、会員絶賛募集中です。)
http://textcode.vs.land.to/GROOVY/TwitterBotGroovy1.zip
まず、Java環境でのHello Worldまでは完了しているものとします。
以下の二つのjarを、以下の位置に配置します。
twitter4j-1.0.4.jar
のふたつのjarを追加します。ここwar以下のファイルはserverに実際にdeployされます、
置き場所は、例えば、
c:\workspace\GroovyBotTemplate1\war\WEB-INF\lib
とかになりまか。
で見えるようになります。
WEB-INF の右クリック->New-Folder で groovyフォルダーを作成します
■Groovletの関連づけ
web.xmlにservlet mappingのルールを追加
以下の2定義でワンセットです。
拡張子がGroovyのファイルは GroovyServletとして名前を共通して与え、そのServletは grovy.servlet.GroovyServlet クラスとして扱いますという意味です。
<servlet>
<servlet-name>GroovyServlet</servlet-name>
<servlet-class>groovy.servlet.GroovyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GroovyServlet</servlet-name>
<url-pattern>*.groovy</url-pattern>
</servlet-mapping>
■Groovletの配置
groovyのフォルダーの下に Hello.groovyという名の groovlet (Groovy Servlet)を置きます。
html.html {
head {
title "Hello"
}
body {
p "Hello from Hello.groovy"
}
}
ここでプロジェクト動かしてみましょう
■ Hello from Hello.groovy が見えること。
http://localhost:8080/Hello.groovy を指定して Groovletが見えることを確認します。
下記の様なHTMLがGroovletによって作られています。
Groovlet便利でしょ。
<html> <head> <title>Hello</title> </head> <body> <p>Hello from Hello.groovy</p> </body> </html>
■今度はTwitter bot の骨格を作って、現在時刻をつぶやいてみましょう。
下記コード Jihoubot.groovyを groovyフォルダに置きます。これを動かしてみましょう。
import java.text.* import twitter4j.* now = new SimpleDateFormat("yyyy/MM/dd HH:MM:SS").format(new Date()) twit = new Twitter("あなたのuserid","あなたのpassword") twit.update("現在の時刻は ${now} ") html.html { head { title "Jioubot" } body { p "posted ${now} " } }
はい、これでご自分のTwitterアカウントに現在時刻が投稿されたでしょうか。
cookieがセットできないとか、時間が日本時間ではないとか
まだいまいちな部分がありますが、これで投稿までは出来ましたね。
投稿用お試しアカウント coolpoco を見ると、
うまくいった時の実行結果が分かると思います。
あと汎用で組み込まなくてはいけないのは
あたりですね。
とりあえず第一回での作業内容としては、このあたりでよいと思います。
Groovyがいい感じだということがおわかりいただけたと思います。
2009-07-21 JavaOne2009の Core Java SEの面白そうな資料のメモ
JavaOne 2009の資料がdownload出来るようになってます。
http://developers.sun.com/learning/javaoneonline/j1online.jsp?track=javase&yr=2009
Core Technology: Java SE and Desktop で、面白そうな資料のリンクメモ
TS-3968.pdf JavaFXとGroovy カヌーのDierk Konigが書いている
TS-4215.pdf Groovy1.6 新機能 GAEで動作させる話もあり
TS-4955.pdf GroovyとJRubyの比較 104ページ
TS-4961.pdf LL Patterns LLでGoFを書くとどうなるか
TS-5061.pdf Teracottaの分散GC 後で理解する
TS-5217.pdf EffectiveJava2からの抜粋?
TS-5301.pdf Hudson Kawaguchiさんスピーカーだったらしい、唯一の日本人では?
TS-5385.pdf Azul VM クラウド的な意味で、後で理解する
TS-5395.pdf ActorベースのScala同期化、なにやら重要そうだが、Scalaの一般理解が先
毎年、全部ダウンロードするが、なかなか呼んでいられない。
2009-06-16 Gr*ワークショップ3で使用した資料
Google Calendarの今のタイムスタンプにつぶやきを記録する、
Google Calendarのライフログ的使い方のサンプルコードを上げました。
2009-03-14 ひらがな->カタカナ変換Groovyスクリプト
各種名簿を整理するついでに、読み仮名を統一したかったので
カタカナをひらがなに変換するGroovyスクリプトを書きました。
// 全角ひらがな -> 全角かたかな変換 def String hira2kata(String a) { a = a.replaceAll(/あ/,'ア').replaceAll(/い/,'イ').replaceAll(/う/,'ウ').replaceAll(/え/,'エ').replaceAll(/お/,'オ') a = a.replaceAll(/ぁ/,'ァ').replaceAll(/ぃ/,'ィ').replaceAll(/ぅ/,'ゥ').replaceAll(/ぇ/,'ェ').replaceAll(/ぉ/,'ォ') a = a.replaceAll(/か/,'カ').replaceAll(/き/,'キ').replaceAll(/く/,'ク').replaceAll(/け/,'ケ').replaceAll(/こ/,'コ') a = a.replaceAll(/さ/,'サ').replaceAll(/し/,'シ').replaceAll(/す/,'ス').replaceAll(/せ/,'セ').replaceAll(/そ/,'ソ') a = a.replaceAll(/た/,'タ').replaceAll(/ち/,'チ').replaceAll(/つ/,'ツ').replaceAll(/て/,'テ').replaceAll(/と/,'ト') a = a.replaceAll(/な/,'ナ').replaceAll(/に/,'ニ').replaceAll(/ぬ/,'ヌ').replaceAll(/ね/,'ネ').replaceAll(/の/,'ノ') a = a.replaceAll(/は/,'ハ').replaceAll(/ひ/,'ヒ').replaceAll(/ふ/,'フ').replaceAll(/へ/,'ヘ').replaceAll(/ほ/,'ホ') a = a.replaceAll(/ま/,'マ').replaceAll(/み/,'ミ').replaceAll(/む/,'ム').replaceAll(/め/,'メ').replaceAll(/も/,'モ') a = a.replaceAll(/や/,'ヤ').replaceAll(/ゆ/,'ユ').replaceAll(/よ/,'ヨ').replaceAll(/ら/,'ラ').replaceAll(/り/,'リ') a = a.replaceAll(/ゃ/,'ャ').replaceAll(/ゅ/,'ュ').replaceAll(/ょ/,'ョ') a = a.replaceAll(/る/,'ル').replaceAll(/れ/,'レ').replaceAll(/ろ/,'ロ').replaceAll(/わ/,'ワ').replaceAll(/を/,'ヲ') a = a.replaceAll(/ん/,'ン') a = a.replaceAll(/が/,'ガ').replaceAll(/ぎ/,'ギ').replaceAll(/ぐ/,'グ').replaceAll(/げ/,'ゲ').replaceAll(/ご/,'ゴ') a = a.replaceAll(/ざ/,'ザ').replaceAll(/じ/,'ジ').replaceAll(/ず/,'ズ').replaceAll(/ぜ/,'ゼ').replaceAll(/ぞ/,'ゾ') a = a.replaceAll(/だ/,'ダ').replaceAll(/ぢ/,'ヂ').replaceAll(/づ/,'ヅ').replaceAll(/で/,'デ').replaceAll(/ど/,'ド') a = a.replaceAll(/ば/,'バ').replaceAll(/び/,'ビ').replaceAll(/ぶ/,'ブ').replaceAll(/べ/,'ベ').replaceAll(/ぼ/,'ボ') a = a.replaceAll(/ぱ/,'パ').replaceAll(/ぴ/,'ピ').replaceAll(/ぷ/,'ブ').replaceAll(/ぺ/,'ペ').replaceAll(/ぽ/,'ポ') a = a.replaceAll(/う゛/,'ヴ') } //test code assert hira2kata("あぜるばいじゃん") == "アゼルバイジャン"
元ネタにしたSEDはこちらですが、GroovyよりもSEDの方がすっきり感がありますね。
y/ぁあぃいぅうぇえぉお/ァアィイゥウェエォオ/ y/かきくけこさしすせそたちっつてとなにぬねのはひふ/カキクケコサシスセソタチッツテトナニヌネノハヒフ/ y/へほまみむめもゃやゅゆょよらりるれろわをん/ヘホマミムメモャヤュユョヨラリルレロワヲン/ s/が/ガ/g s/ぎ/ギ/g s/ぐ/グ/g s/げ/ゲ/g s/ご/ゴ/g s/ざ/ザ/g s/じ/ジ/g s/ず/ズ/g s/ぜ/ゼ/g s/ぞ/ゾ/g s/だ/ダ/g s/ぢ/ヂ/g s/づ/ヅ/g s/で/デ/g s/ど/ド/g s/ば/バ/g s/び/ビ/g s/ぶ/ブ/g s/べ/ベ/g s/ぼ/ボ/g s/ぱ/パ/g s/ぴ/ピ/g s/ぷ/プ/g s/ぺ/ペ/g s/ぽ/ポ/g s/う゛/ヴ/g
2009-02-14 デブサミ2009に行ってきました。
デブサミ2009に行ってきました。
http://codezine.jp/trackback/devsumi2009/
JGGUG (Japan Grails/Groovy User Group)ジェイガクとして正式発足しました。
山田さんがLTしている様子がUstreamで分かります (01:07:28〜)
http://www.ustream.tv/recorded/1146074
2009-01-19 ファイルの添え番号の桁を3桁に揃えるGroovyスクリプト
開始ディレクトリー以下にあるjpgファイルの添え番号の桁を3桁にそろえるGroovyスクリプト
FlashExtracht でフラッシュファイルから画像を抽出したりした時には、
フラッシュの中のjpegのファイル名か hoge[1].jpg とか hoge[11].jpg とかになって出てくるわけですが、この場合、ソートして見ようと思っても、hoge[1].jpg,hoge[10].jpg,hoge[100].jpg
の様にしか並ばないので、元々の画像の並び順に意味があった場合には、不都合が生じます。
そこでソート可能な様に全ての添え番号を3桁に揃えるGroovyスクリプトを書きました。
例えば
hoge[11].jpg --> hoge[011].jpg
という風にリネームします。
padLeft()を使ってコード短縮しました
// 開始ディレクトリー以下にあるjpgファイルの添え番号の桁を3桁にそろえる // 例:hoge[10].jpg --> hoge[010].jpg new File(".").eachFileRecurse { file -> if(file.isFile() && file.name.endsWith("jpg")) { name = file.getName() newname = name newname = file.getName().replaceAll(/\d+/){ it.padLeft(3, '0') } if (name != newname) { println name+" renamed to "+newname file.renameTo( new File(file.getParent()+"/${newname}") ) } } }
2009-01-18 Groovyなう&ふゅーちゃーに出席しました。
Groovyなう&ふゅーちゃーに出席しました。
Groovy1.6の最新情報です。
私はまだ1.5ユーザーですが、1.6を使いたい理由は、速い、safe reference operatorが使える。
Java7との親和性も当然高まっています。
資料:
http://grails-ja.googlegroups.com/web/GroovyNowAndFuture.ppt
http://www.ustream.tv/channel/grailscodereading-16
以下は、出席したときのメモ書き
Groovy 1.6について
エルビス演算子 ?:
三項演算子相当
A?: B とは if(A) {A} else {B}
Java7のは safe reference operator相当 Rubyの場合は .? と書く
Class A {
B b;
}
Class B extends A{}
はコンパイルできなかった "groovyc -j" で実行可能
JavaScriptの様に、クラスも、インスタンスも動的にメソッド書き換え可能、
無秩序すぎないか、
Grailsだったらmetaclassの中でのみ動的な変更可能となっており、整理できる。
Expando Meta Class (EMC)
多重代入
分岐してもreturn省略可能
AST変換
実行時Mixed-in
ツールGrape
最初は、Javaの数十倍遅かった、
The Computer Language Bechmarks Game a.k.a "shootout"
1.5.6までは遅かったが、1.6からは速い ただし起動は遅くなった
メソッド呼び出しが高速化した JRubyはRuby1.9相当の速度
"CallSite" cache の実装、2回目以降は、呼び出し側が保持する、みつけたmethodを再利用する
expandoMetaclassであっても発見容易
"CallSite-Array"という新規な変数を持ち、探索コストがなくなる
DefaultGroovyMethod#additionals を参照
インライン展開 HotSpot Deoptimization
Maven/RubyGems みたいなもの Ivyとはモジュール管理に特化したMaven
走行中もDownloadできる
Grape.grab(group:'org.jidesoft',version:':[2.2.9)'))
"xxx".metaClass.a ={print "hello"}
"xxx".a()
AST変換
Groovyとしてsyntex errorを起こすものは変更できない
@Bindable / @Vetoable = Java.beans.propertyChangeSupport
@Immutable
@Lazy 遅延生成
@Category / @Mixin
@PackageScope
Retention Policy = Source の扱い、多分マクロの位置づけ
String.mixin Date
assert "a".getTime() == xxxxx エポックからの時間が分かる、意味不明になりがち
マルチ代入
def (a,b) =[1,2] <-- def a=1; def b=2 のこと
if(x%2==0) {true} else {false} <-- 2カ所でreturnできる
EMC DSL 一気にメソッドが定義できる String.metaClass.define { ここにメソッドがいっぱ書ける}
これでメソッドが中途半端に追加された状態が隠せる
Grape の annotation表記は冗長
2008-12-04 Groovy Clousureは、Methodではないので全ての処理が終わらないと終
Groovy Clousureは、Methodではないので全ての処理が終わらないと終了しない件
今回特にためになったのは、Closureの挙動について、その終了の仕方がMethodとは異なること。
つまりClosureはMethodsではないので、もらった入力は全て処理する。
[1,2,3].each {print it; return } この出力は"123" 全て処理してから終わる
for (it in [1,2,3]) {print it; return} この出力は"1" ひとつの出力で終わる
もう一つ確認
1.upto(3) { print it ; if (it>1) return} この出力は"123" 全て終わってからreturnする。
returnを処理の途中で発生させても、println it の部分の処理は10まで進みます。
2008-11-26 第16回オープンソーステクノロジー勉強会に行ってきました。
MapReduceの話を伺いにGREE Labsにお邪魔してきました。
以下メモ書き
Preferred Infrastructure 太田一樹さん http://kzk9.net/ http://preferred.jp/
Sedue 分散検索エンジン
Hadoop + EC2 の分散検索
SOSP学会
200億ページ 20kb = 400TB がインターネットの全体 読み込みは100日 400GBが1000台あれば良い
MPI = Massage Passing Interface が並列プログラミングのライブラリ
Framework側で持つ
1jobあたり5プロセスが死ぬ
用途
Sort
Log analysis
Web Graph generation
Machine Learning
Inverted index Construction
Machine Learning
K-means
Apache ツール出てきた
hadoop Distributed File System
HDFS = Master/Slave Architecture
64MB単位に分割
Namenode + Datanode (NamenodeはentryでSPOF)
Master = Jobtracker 事業のタスク分割 全てのTracktrackerへ定期pingを打つ
Slave = Tasktracker
Hadoop streaming は 多言語interface : Rubyからでも呼べる
はてぶもHadoop
FacebookがhiveというHadoopのラッパーを作った
GFSはAppendできるがHadoopはまだできていない
Hadoopでもlog rotation みたいな仕掛けは使える。
読み込み元のデータとの同期は、できない Latencyは、発生しうる
Javaのthread にはHadoopは勝てない、tasktrackerのlaunchとか、相当overheadがかかる。
大倉努さん http://ohkura.com blogeye
Hadoop + EC2
著者推定
300GBのデータマイニング
EC2 = 10cent/hour 1時間10円
Hadoopは後からnode追加、削除可能 障害マシンの除去可能
S3 + mySQL使用
クローラーは落ちやすい
MySQLにデータを置いて重複検知 Hadoopは小さいファイルが苦手
記事の合体
MappertがReducerに送るとき、途中で共有ファイルシステム上に置かれて、そのファイル名が渡される。
ReducerはMasterに聞いて必要なデータが揃っていたらHTTpで取りに行く
ヤスタケさん
300GくらいならS3でなくEC2で間に合うかも LOCALのデータは EC2の上のデータは消える
アマゾンに1年で40万くらい払った
CRAWLのジョブはつまらない 2〜3台で間に合う
EC2の仮想マシンは、大中小とあるがどれか、1年前は1種類しかない dual coreはあまりメリットない
一台のマシンにMapperとReducerと両方入れて置いた方が良い、同じマシン内部での処理は有利
Hadoopの駄目な点、あまり再起動はない、MasterでCrawlしていたから
Hadoopじゃなくては駄目な理由は?
2008-08-31 ”ProjectZeroでPHPパート2” PHP勉強会で発表
2008-08-11 Grovyコンファレンスのスピーカーの方々(一部)
Groovyコンファレンスのスピーカーの方々のリンク集。
キムゾー氏
http://d.hatena.ne.jp/kimzo/comment?date=20080717§ion=1216312904#c :title=http://d.hatena.ne.jp/kimzo/comment?date=20080717§ion=1216312904#c
]
nobusue氏
http://d.hatena.ne.jp/nobusue/20080717
uehaj氏
山田正樹氏 (今回は進行とかで参加)
http://www.metabolics.co.jp/mmw/
るいも氏
竹嵜 伸一郎氏
http://reflex.sourceforge.jp/index.html
今回は、私は発表しません、Guestの方優先にしています。
2008-08-03 seasarcon 2008 Autumn でLTします
2008-07-30 どう書く? org の2次元ランダムウォークの課題回答
どう書く? orgの課題回答です。Groovyを使用しています。
の課題の回答です。どう書く? orgには画像が投稿できないので、画面イメージはこちらに置きます。
コードはこちら。
import groovy.swing.SwingBuilder import java.awt.Color import java.awt.BorderLayout as BL import javax.swing.WindowConstants as WC import javax.swing.BorderFactory as BF import javax.swing.JOptionPane swing = new SwingBuilder() paint = swing.action( name: 'Run', closure: this.&paintGraph, mnemonic: 'R', accelerator: 'ctrl R' ) about = swing.action( name: 'About', closure: this.&showAbout, mnemonic: 'A', accelerator: 'F1' ) frame = swing.frame(title:'2次元ランダムウォーク', location:[100,100], size:[300,300], defaultCloseOperation:WC.EXIT_ON_CLOSE) { menuBar (){ menu(mnemonic:'A','Action'){ menuItem(action:paint) } glue() menu(mnemonic:'H','Help'){ menuItem(action:about) } } panel (border:BF.createEmptyBorder(6,6,6,6)) { borderLayout() vbox(constraints: BL.CENTER,border:BF.createTitledBorder('Runボタンを押すたびに100回動きます')) { panel(id:'canvas') } hbox (constraints: BL.SOUTH){ hstrut(width:10) button(action:paint) } } } frame.show() def labeledSpinner(label, value){ swing.label(label) swing.hstrut() swing.spinner(id:label, stateChanged:this.&paintGraph, model:swing.spinnerNumberModel(value:value)) } gfx = swing.canvas.graphics gfx.color = new Color(255, 255, 150) gfx.color = Color.red xpos = 100 ypos = 100 def paintGraph(event) { int width = swing.canvas.size.width int height = swing.canvas.size.height 1.upto(100) { xdir = Math.random() ydir = Math.random() if (xdir <0.3333 && xpos >5) { xpos-=5 } if (xdir >0.6666 && (xpos < width-5)) { xpos+=5 } if (ydir <0.3333 && ypos >5) { ypos-=5 } if (ydir >0.6666 && (ypos <height-5)) { ypos+=5 } gfx.fillRect(xpos,ypos,4,4) } } void showAbout(event) { JOptionPane.showMessageDialog(frame, '''2次元ランダムウォーク 赤い四角がランダムに歩きます。''') }
2008-07-27 「Java並行処理プログラミング」最終回
Java読書会の「Java並行処理プログラミング」最終回でした。
最終回は Hackathon的にIPV6での接続テストを実施しました。
Windows XPで実施する場合、以下のコマンドが事前に必要です。
私はWindows XP + Wireless で接続しました。
> netsh interface ipv6 set privacy disabled persistent
> ipv6 -p gpu UseTemporaryaddresses
Java並行処理プログラミング ―その「基盤」と「最新API」を究める―
- 作者: Brian Goetz,Joshua Bloch,Doug Lea
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2006/11/22
- メディア: 単行本
- 購入: 21人 クリック: 318回
- この商品を含むブログ (156件) を見る
2008-06-29 ProjectZeroでPHP
ProjectZeroでPHP という話を第34回PHP勉強会でLightning Talkしました。
http://events.php.gr.jp/event.php/event_show/46
発表10分
ProjectZeroでPHPを始めるまでの話。
Presentation
Google Docs のプレゼンテーション「ProjectZeroでPHP」
http://docs.google.com/EmbedSlideshow?docid=dc9bnsx3_6009k22c5cd
Video
ちょっと補足
Groovy in Action の和訳がもうじき出ます。
- 作者: Dierk Konig,Andrew Glover,Paul King,Guillaume Laforge,Jon Skeet
- 出版社/メーカー: Manning Pubns Co
- 発売日: 2007/01
- メディア: ペーパーバック
- クリック: 5回
- この商品を含むブログ (8件) を見る
バイブル的な本なので、これ一冊で足りると思います。
ProjectZeroのアプリケーション記述言語は GroovyとPHPの2種類です
という二択になります。
http://www.c-sq.com/modules/article/article133.html
のFloyd Marinescu氏の資料を参照。
- JavaをRubyの様な表記で使える
- 低い学習コスト
- 無茶な動的化はせず、最終的には、「亜Java速」を狙っている。
- 過去のJava資産との親和性が高い。
- コンパイルして、普通のjarにしてしまえる。
- 対象者はJava使いに特化している
あたりが理由です。
2008-06-24 テキストマイニングのセミナーがあります。
さりげなく、書いてしまいますが、
7月11日に、テキストマイニングに関するナイトセミナーがあります。 (3人称的に書いていますが、中の人です)
Information Retrieval に関心のある人には良いかも。
「可能性を拡げるテキストマイニング 〜適用事例から先端研究動向まで〜」
http://www.ibm.com/developerworks/jp/evangelist/events/080711.html
解説文が高尚で分かりにくいかもしれませんが、炎上探知機の技術解説と言えば分かりやすいかもしれません。
日本語の構文から意味解釈して、コメント自体が全体でPositiveかNegativeか判定するという
評判分析の話です。 炎上学に興味のある人などに向くかもしれません。
入力フォームの書式が形式的で堅く、エントリーしてもAutoResponseのメールも来ませんが、
特に制限なく、どなたでもエントリー可能です。
ついでにその1週間前の
7月4日「SOA実装設計 〜SOAインフラの下流の設計方法論〜」
は、WS-ReliableMessagingの話があります (こっちは中の中の人)
2008-06-20 RESTful読書会第3回に出席しました
RESTful読書会第3回に出席しました。
- 作者: Leonard Richardson,Sam Ruby,山本陽平,株式会社クイープ
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2007/12/21
- メディア: 単行本
- 購入: 20人 クリック: 623回
- この商品を含むブログ (168件) を見る
30分ほどいただいて、ProjectZeroの話をしました。
動画はこちら、うしろが切れているっぽいです。id:i_ogiさん、ありがとうございました。
その時使用した資料はこちらです。










ファイル名の数値が含まれる箇所が一箇所だけなら、
text.replaceAll(/\d+/){ it.padLeft(3, '0') }
のようにすると簡単に3桁に変換できます。
コード、ブラッシュアップしました。