はてなキーワード: Stringとは
/** * そっとうに。 * * そっとうにを置く。 * * @param string $str * @return string * @see <a href="http://vipsister23.com/archives/5204131.html">とある小学生が書いた詩が哲学的過ぎる件</a> */ function sottoUni($str) { return 'そっと' .PHP_EOL . $str.'に' .PHP_EOL .'うに' .PHP_EOL; } $arr = array('せなか','わたげ','たにま'); foreach($arr as $d) { echo sottoUni($d); }
RubyのSymbolと文字列の違いを研究室の輪講用に書いたのですが,折角なので公開したいと思います.
元々学部生に対する輪講用に書いた物なので,若干上から目線ですがご了承ください.
文字列とSymbolはよく似ています.プログラマから見ればどちらも文字列です.違いを一言で説明すると『プログラムが扱う』文字列か,『プログラマが見る』文字列かの違いです.例えば変数名は『文字列』ですが,rubyのオブジェクトである『文字列』ではないですよね?
例えば,今あなたがC言語でお絵描きライブラリを作っているとしましょう.その中に,色で塗りつぶすfillという関数があり,色を青・赤・緑の3色から選べ,fillの引数でそれを指定できるとしましょう.
fillの引数の設定方法として一番単純なのが,0を青,1を赤,2を緑として,0〜2で選択させる方法でしょう.しかし,それでは,どの数値が何色か覚えないといけないし,fill関数を知らない人から見れば,どういう意味の引数かすらさっぱり分かりません.
ではどうするかと言えば,普通はBLUE = 0, RED = 1, GREEN = 2と適当に定数を設定して,その定数を引数で指定させますよね.
こうして,fill関数の引数が意味の無い数値から意味のある文字列に変わったことによってプログラムが分かりやすい物となります.さて,ここで注意してほしいのは,ここで言う文字列はプログラムが扱うオブジェクトとしての文字列では無いということです.fill関数の引数として,"BLUE","RED", "GREEN"などとC言語の文字列を渡すということは普通しませんよね.それは,ここで言う文字列は,あくまでプログラマがプログラムコードを分かりやすくするために必要な文字列であって,プログラムがオブジェクトとして扱う(例えば,長さを求めるとかする)文字列ではないからです.
分かってきたでしょうか?
プログラムコード上では(つまりプログラマから見れば)どちらも同じ文字列(文字の列という意味で)ですが,実際に動くプログラムから見れば単なる数値と本物の文字列という大きな違いです.結局,fill関数の引数の具体的な値は何でもいいわけです.プログラマから見て文字列であればそれだけでよく,プログラムが動くときの実際のその中身は何でもいいわけです.これのために存在するのが,Symbolであり,:fooとひとたびSymbolを作成すれば:fooの実態は適当な数値となります.(この数値がいくらかなんていうことはもちろん気にする必要はありません)
そして,もちろん同じプログラム上では:foo == :fooはちゃんと成り立ちます.もうここまでくれば,Hashのkeyとして文字列でなくSymbolを使う理由が分かりますね.Hashのkeyはあくまで,プログラマが見る(プログラムコードを分かりやすくするための)文字列であってプログラムが扱うオブジェクトとしての文字列では無くて,keyの実際の値は何でもいい,からですね.(特別な場合を除いて)Hashのkeyに対してrubyのStringのメソッドを使うなんてことは無いですよね.
しかし,他の軽量言語ではSymbolなどなくHashのkeyとして普通に文字列を使うことが多いです.では,なぜrubyだけSymbolを使うのでしょうか.
その答えは一言でいうと,rubyの(プログラムコード上に直接書かれた,つまりリテラルの)文字列は他の言語と違いimmutable(不変)でない,からです.実際,pythonやjavascriptの文字列(リテラル)は破壊的に変更することはできませんが,rubyの文字列は破壊的に変更することができます. ('abc'.concat('d')の様に)
これがどういう違いを生むかというと,コード上に直接現れる文字列がimmutable(不変)であるならば,実行時に一つだけそのオブジェクトを作成し,後はそれを使いまわすという最適化ができます.
そうした時,Hashのkeyの様なプログラマから見た文字列というのは,プログラムコード上のリテラルとして現れるわけですが,これらは実行時に一つだけオブジェクトが作成され(特にコード上に現れる同じ文字列は全て一つのオブジェクトにまとめると),それらの比較はそれらに対する参照(そしてこれは大抵メモリのアドレスなど単なる数値)の比較で済むので,結局Symbolと同じ様な働きをするわけです.
本当はプログラマが見るためだけの文字列だけど,それをオブジェクトとしての文字列としても,Symbolと同じ様な働き,パフォーマンスが得られるならば,別にオブジェクトとしての文字列であってもいいわけです.
繰り返しになりますが,プログラマが見るためだけの文字列は,その中身・実態は何でもいいわけですが,その実態がオブジェクトとしての文字列でも十分なパフォーマンスが得られるならば,別にオブジェクトとしての文字列でもいいわけです.
さて,rubyに話を戻しますと,rubyはコード上に現れる文字列であっても,実行時にそのコードを通る度に毎回新たな文字列オブジェクトを作成します.
(以下のプログラムを動かすことで確認できる.)
def foo 'foo'.object_id end p foo, foo
つまり,rubyでは文字列が可変であるため,先に述べたような最適化ができない(または難しい)ので毎回新たな文字列オブジェクトが作成されるのです.
こうなると,先ほどの話とはうってかわって,プログラマが見る文字列はその実態は何でもいいのに,それを文字列リテラル(rubyのオブジェクトとしての文字列)にしてしまうと,毎回毎回文字列オブジェクトが作成されてしまうという非常にばかばかしい状況になってしまいます.我々はそれらの文字列オブジェクトに文字列としての操作は一切施さないのにも関わらず,です.
こういうわけで,rubyではプログラマが見るためだけの文字列にSymbolというruby特有のものを使うのです.
もちろん,プログラマが見るためだけの文字列を全て定数として(そしてもちろん中身は適当な値で)定義しても構わないわけですが,Hashのkeyとかで数多くのプログラマが見るためだけの文字列が現れることを考えると,とてもじゃないですけどそんなことは面倒でやってられないですよね.ですので,実行時に自動で適当な値にしてくれるSymbolというものが存在するのです.
以上で,Symbolについての説明を終えます.以下は蛇足です.
最初の方で出てきたfill関数をrubyで実装しようとしたとき,青・赤・緑の各色はその実際の値はなんでもいいのでrubyのSymbolを使って:blue, :red, :greenとしてもいいのですが,ライブラリとかでは大抵ちゃんと定数として定義されていることが多いです.
これは恐らく,定数として明示的に定義することで値の存在を明示でき,ドキュメント化の際にも役立つことによっているのでしょう.
しかし,あくまでこれは外部に公開するようなライブラリでの話であって,自分が使うちょっとしたプログラムならこういう場面でも精力的にSymbolを使っていってもいいと思います.ちなみに,僕ならSymbolを使います.
Symbolだと定義もいりませんし,定数は大文字ですから打つのが面倒ですし,あまりソースに大文字が入ると見た目がすっきりしません(主観).
Symbolは非常に便利なものですので,その意義・用途を十分に理解して,Hashのkeyにとどまらず様々な所で使えるようになりましょう.
Javaだけど。
class HelloWorld { public static void main(String args[]) { System.out.println("Hellp World"); } }
Web屋のネタ帳( http://neta.ywcafe.net/ )様の
これからの「パスワード」の話をしよう( http://neta.ywcafe.net/001184.html )で
紹介されているパスワードのハッシュ化のバグについて突っ込んでみる
「1回ハッシュ化を解読できただけ、プレーンパスワードを入手することが可能である」
というものである。
問題の部分はここ
/**
* 平文のパスワードをハッシュ&stretchするメソッドです。
* loop回数は1000としていますが、999でも1001でもお好みでどうぞ。
* ただしループ回数は処理時間に直結しますのでほどほどの数値で。
*/
private static final String hashAndStretch(String plainPasswd, String salt) {
int loop = 1000;
String hashedPasswd = "";
for (int i = 0; i < loop; i++) {
hashedPasswd = DigestUtils.sha256Hex(hashedPasswd + plainPasswd + salt);
}
return hashedPasswd;
}
<凡例>
ソルト:SSSSSSSS
<トレース>
XXXXXXXX ← DigestUtils.sha256Hex("YYYYYYYY" + "PASSWORD" + "SSSSSSSS")
クラッカーがXXXXXXXXXのハッシュ値を解析し、元の文字列が「YYYYYYYYPASSWORDSSSSSSSS"」と判明したとする。
この時点で元文字列の中にプレーンパスワードが含まれていることになる。
また、ハッシュ化された文字列には「0123456789abcdef」の文字しか含まれておらず、
「それ以外の文字が含まれていた場合容易にプレーンパスワードではないか」
一般的なパスワードには少なからず「0123456789abcdef」以外の文字が含まれているだろうし、
上記のことをふまえてプログラムを修正すると。。
/**
* 平文のパスワードをハッシュ&stretchするメソッドです。
* loop回数は1000としていますが、999でも1001でもお好みでどうぞ。
* ただしループ回数は処理時間に直結しますのでほどほどの数値で。
*/
private static final String hashAndStretch(String plainPasswd, String salt) {
int loop = 1000;
String hashedPasswd = DigestUtils.sha256Hex(plainPasswd + salt);;
for (int i = 0; i < loop; i++) {
hashedPasswd = DigestUtils.sha256Hex(hashedPasswd + DigestUtils.sha256Hex(salt + i));
}
return hashedPasswd;
}
旭茉莉(昆蟲白)、Happy New-Yearが言いたくて(南野陽子)、一直到底(Nipples)、赤い戦車(ヤプーズ)、南方蝶道(甜梅號)、
一個人的水道(甜梅號)、Air on the G string(Bach)、春夏秋(チャットモンチー)、激光中(羅文)、Merry Christmas Mr. Lawrence(坂本龍一)、
恋愛スピリッツ(チャットモンチー)、安眠藥(歐陽靖 陳奐仁)、甜蜜蜜(薛凱琪)、MAY(斉藤由貴)、ダンシング・ヒーロー (荻野目洋子)、
雙失情人節(Twins)、青山黛瑪(何韻詩)、汽水樽裡的咖啡(何韻詩)、情歌(側田)、when i listen to the field mice(my little airport)、
習慣失戀(容祖兒)、糖不甩(薛凱琪)、VALON-1(Salyu)、戀人未滿(S.H.E)、美空雲雀(何韻詩)
東風(Yellow Magic Orchestra)、Lucky(スーパーカー)、我有一段情(吳鶯音)、曙(ゲルニカ)、2EM12_KK_A09(ヱヴァ破)、
光榮之家(何韻詩)、北歐是我們的死亡終站(my little airport)、隆重登場(容祖兒)、電力組曲 C:電化の暮らし(ゲルニカ)、妮歌(何韻詩)、
Komm, Susser Tod/甘き死よ、来たれ(Arianne )、ホープ(testpattern)、給十年後的我(薛凱琪)、安靜了(S.H.E)、女朋友(歐陽靖 陳奐仁)、
体操(YMO)、You Only Live Twice(Nancy Sinatra)、小茉莉(楊丞琳)、Oh!(少女時代)、圓謊(容祖兒)、
管他什麼音樂(范曉萱&100%)、Blue Paradise(Martin Denny)、泡泡(魏如萱)、Sunny Road To Salina(Christophe)、Be True(容祖兒)、
優しいたそがれ(南野陽子)、最後的歌(楊千嬅)、Le premier chagrin d'amour(France Gall)、眼球綺譚(戸川純ユニット)、愛しのキッズ(小島麻由美)、
月世界旅行(アポジー&ペリジー)、韻律泳(何韻詩)、飛べない翼(Lily Chou Chou)、手のなるほうへ(チャットモンチー)、ヒステリヤ(ヤプーズ)、
Green Grass Of Tunnel(Mum)、夢伴(梅艷芳)、舊約(何韻詩)、再見...露絲瑪莉(何韻詩)、AXIA~かなしいことり~(斉藤由貴)、
就算世界無童話(衛蘭)、점핑(Kara)、夢のスキマ(鷺巣詩郎)、空しき流れ(鷺巣詩郎)、閉塞の拡大(鷺巣詩郎)
那年夏天寧靜的海(王心凌)、痛愛(容祖兒)、落寞莉(昆蟲白)、憤怒の河(戸川純)、惚たる蛍(チャットモンチー)、
愛一個上一課(容祖兒)、最後一課(容祖兒)、時不與我(容祖兒)、Dear. Mom(少女時代)、男孩像你(薛凱琪)、
沙堡壘(容祖兒)、A Wishful Way(Hopscotch)、ONE(斉藤由貴)、拳銃(チャットモンチー)、脆弱(謝安琪)、
立つ鳥跡を濁さず(トップをねらえ2!!)、時の河を越えて(トップをねらえ!)、親知らず(チャットモンチー)、媽媽我考試考100分(selfkill)、搜神記(容祖兒)、
想想(何欣穗)、リフトの下で逢いましょう(南野陽子)、ギルガメッシュ(ヤプーズ)、Roller Coaster Rock(selfkill)、a love song(EGO-WRAPPIN')、
愛將(梅艷芳)、手のなるほうへ(チャットモンチー)、petsounds(the beach boys)、香格里拉(魏如萱)。
というわけでサンプルコード書きなおしてみた。
public class Main { public static void main(String[] args) { int count= args.length==0?100000:Integer.parseInt(args[0]); long start=System.currentTimeMillis(); Main m=new Main(); double result=0; for(int i=0;i<count;i++){ result+=m.test((double)(0.1f*i)); } System.out.println(result); System.out.println(String.format("COMPLETE! %d msec",System.currentTimeMillis()-start)); } private double product=0; public double test(double rad){ return this.product+=Math.tan(rad); } }
<?php class Test{ private $product; public function test($rad) { return $this->product+=tan($rad); } } $count =is_null($argv[1])?100000:(int)$argv[1]; $start=microtime(true); $t=new Test(); $result=0; for($i=0;$i<$count;$i++){ $result+=$t->test(0.1*$i); } echo "{$result}\n"; printf("COMPLETE! %f msec", (microtime(true)-$start)*1000);
$java -jar test.jar 100000 -7.524990063072938E9 COMPLETE! 31 msec
$ php -f test.php 100000 -11900078829.3 COMPLETE! 209.314108 msec
うむ。有意な差はあるっぽいな。(結果が違い過ぎてるのはなんか問題があるかもしれん)
多分、変数の型が出鱈目で計算されるようなもんだとPHPは遅くなるのだと思われ。javaは強い型制約があるから、同じ型同士の計算だと速いとか?
サンプルコード。
package test; public class Main { public static void main(String[] args) { int count= args[0]==null?10000:Integer.parseInt(args[0]); long start=System.currentTimeMillis(); Main m=new Main(); for(int i=0;i<count;i++){ System.out.println(m.test()); } System.out.println(String.format("COMPLETE! %d msec",System.currentTimeMillis()-start)); } public String test(){ return "ぽぽぽぽーん"; } }
<?php class Test{ public function test(){ return "ぽぽぽぽーん"; } } $count =is_null($argv[1])?10000:(int)$argv[1]; $start=microtime(true); $t=new Test(); for($i=0;$i<$count;$i++){ echo $t->test()."\n"; } printf("COMPLETE! %f msec", (microtime(true)-$start)*1000);
ぽぽぽ...
COMPLETE! 1008 msec
ぽぽぽ...
COMPLETE! 988.869190 msec
どういうことなのか説明してもらおうか?
http://okajima.air-nifty.com/b/2011/01/2011-ffac.html
ぷよぷよを解く問題をやってみた
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { StringBuilder[] blocks = { new StringBuilder("**GYRR"), new StringBuilder("RYYGYG"), new StringBuilder("GYGYRR"), new StringBuilder("RYGYRG"), new StringBuilder("YGYRYG"), new StringBuilder("GYRYRG"), new StringBuilder("YGYRYR"), new StringBuilder("YGYRYR"), new StringBuilder("YRRGRG"), new StringBuilder("RYGYGG"), new StringBuilder("GRYGYR"), new StringBuilder("GRYGYR"), new StringBuilder("GRYGYR") }; bool updated = true; while (updated) { breaked: DumpBlock(blocks); for (int i = 0; i < blocks.Length; i++) { for (int j = 0; j < blocks[i].Length; j++) { char c = blocks[i][j]; if (c == '*') continue; updated = false; if (KillBlocks(blocks, i, j)) { updated = true; goto breaked; } } } } DumpBlock(blocks); Console.Read(); } struct Point { public int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } static bool KillBlocks(StringBuilder[] blocks, int x, int y) { bool[,] visted = new bool[blocks.Length,blocks[0].Length]; MarkBlock(visted, blocks, x, y); Queue<Point> queque = new Queue<Point>(); for (int i = x; i < blocks.Length; i++) for (int j = y; j < blocks[i].Length; j++) if(visted[i,j] == true) queque.Enqueue(new Point(j,i)); if (queque.Count < 4) return false; while (queque.Count > 0) { Point p = queque.Dequeue(); RemoveBlock(blocks, p.x, p.y); } return true; } static void MarkBlock(bool[,] visted, StringBuilder[] blocks, int x, int y) { if (x < 0 || y < 0 || x >= blocks.Length || y >= blocks[0].Length || visted[x, y] == true) return; char c = blocks[x][y]; visted[x, y] = true; if (x + 1 < blocks.Length && blocks[x + 1][y] == c) MarkBlock(visted, blocks, x + 1, y); if (y + 1 < blocks[0].Length && blocks[x][y + 1] == c) MarkBlock(visted, blocks, x, y + 1); if (x > 0 && blocks[x - 1][y] == c) MarkBlock(visted, blocks, x - 1, y); if (y > 0 && blocks[x][y - 1] == c) MarkBlock(visted, blocks, x, y - 1); } static void DumpBlock(StringBuilder[] blocks) { foreach (StringBuilder s in blocks) Console.WriteLine(s); Console.WriteLine(); } static void RemoveBlock(StringBuilder[] blocks,int x,int y) { int i; if (y == 0) { blocks[y][x] = '*'; return; } for (i = y; i > 0; i--) { blocks[i][x] = blocks[i - 1][x]; } blocks[i][x] = '*'; } } }
わざわざ外に出して関数化するほどのことでもないよな、とか
この関数からしか呼ばないのに、並列に関数を置きたくないな、とか思うことがあるでしょう。
JavaScript ならこんな思いに見事に答えてくれます。
たとえば個人情報が云々なので文字列のマスク処理を作ろうとしましょう。
String.prototype.mask = function() { var maskedText = ""; for(var ix = 0; ix < this.length; ix++){ maskedText += mask1(this.substring(ix, 1)); } return maskedText; function mask1(character) { var maskedCharacter = ""; swith(chr) { case 数字: 処理A, 個別処理 case 英字: 処理B, 個別処理 case 全数字: 処理A, 個別処理 case 全英字: 処理B, 個別処理 case ひらがな: 処理C, 個別処理 case カタカナ: 処理C, 個別処理 case 漢字: 処理D, 個別処理 default: 未処理 } return maskedCharacter; } };
こういうメソッドを作った時、処理A、処理B、処理Cは冗長な処理になっているわけです。
個別処理があるのでbreakしなければいいや、というわけでもありません。
しかしこの処理A,B,Cはこの関数外に置くような処理でもないわけです。
この関数内でしか使いませんし、むしろ使って欲しくないわけです。
function mask1(character) {
var maskedCharacter = "";
swith(chr) {
case 数字:
shoriA(), 個別処理
case 英字:
shoriB(), 個別処理
case 全数字:
shoriA(), 個別処理
case 全英字:
shoriB(), 個別処理
case ひらがな:
shoriC(), 個別処理
case カタカナ:
shoriC(), 個別処理
case 漢字:
処理D, 個別処理
default:
未処理
}
return maskedCharacter;
function shoriA() { 処理A }
function shoriB() { 処理B }
function shoriC() { 処理C }
}
こう書けるのです。
JavaScript で一番好きなのはこの内部関数です。
2010年の年末から年始にかけて10連休ほどあったので、新しいサイトを作ろうと思い立った。
月に1万円だと、毎日コーヒーを飲んでるだけでなくなってしまうので、コーヒー代くらい稼げたらうれしいなあ。じゃあどうする。何を作る?
ということで、まずTwitterを使ったものを作ることにした。
ひとつのジャンルにしぼってツイートをかき集めれば、面白い流れになるんじゃないか。人が来るんじゃないか。そう思った。togetterみたいな。で、ジャンルは、個人的に興味がある子育て。ていうか毎日帰宅してから朝まで子どもの寝かしつけや夜泣きの対応でサイトを更新する暇も、俺が寝る暇もあんまりない。ので、手がかからないことが大前提。なんだったら自動更新でもいい。
自動更新かー。と思って「ブログ 自動更新」でググったら、wordpressにRSSから更新するプラグインがあるらしいことを知った。はい決定。その瞬間、「TwitterのAPIからRSSを引っ張ってwordpressに投稿するサイト」に決まった。
さくらインターネットのスタンダードを申し込んだ。14日お試しがあるらしいけど、仮申し込みの時点で住所も入れてコンビニ請求にしたら、数日後に請求書が送られてきてビビった。(同時にドメインも申請しちゃった)
まあ、webで申し込んで、すぐにサーバコントロールパネルという画面に入れるようになった。「クイックインストール」というリンクがあったので見てみたらMovableTypeとWordPressを自動でインストールしてくれるらしかったので、ボタンを押した。インストールできましたというので発行されたURLをクリックしたけど404だった。1時間くらい404で、その日はもう寝た。
次の日の夜。これはもう、10連休を利用して毎晩1時間ずつ捻出するしかない、さくらのお試し14日あるから約14時間で作りきるしかねえ、と思った。
サイトにアクセスしたらwordpressが入ったページが出てきた。おお、サイトができてる!
まずTwitterを調べるか、と思って、「Twitter API」で検索したけどOauth?とかいう面倒なことをしないといけないらしかったのでやめた。じゃあ普通に検索は?と思って「Twitter 検索」で検索したら、search.twitter.comの結果はjsonかatomで取得できるし、APIコール制限もないらしいのでこれに決定。検索だけで1時間たった。
夜も更けて、続けて作業した。「wordpress xml 投稿」で検索していくつか探したらFeedWordpressというプラグインがあったので入れた。あ、事前知識としてMovableTypeでのブログはやったことがあったので、プラグインを入れるみたいな話はスムーズに進められた。
で、twitterの検索結果をatomで返した結果を入れてみた。ら、本当に投稿されてた。よっしゃできた、と思った。1ツイートが1エントリになってたし、投稿者もツイートした人になってた。よかった。でも、満足できなかった。
次の日。同じことを自力でやる方法を探した。「wordpress xml 投稿」で検索して、XMLをパースできるようになればいいんじゃないかと思い、simplepieというPHPライブラリにたどり着いた。が、PHPなんてまったく知らないし、憶える気もなかった。actionscriptで書かせてよ、とずっと思ってた。
次の日。「wordpress xml 投稿」でまた検索。どうやらwordpressの投稿って、xmlrpcというやり方を使ってるらしかった。ので、「wordpress xmlrpc 自動投稿」で検索したら、なんかサンプルコードが載ってたのでそのまんまコピペ(結局PHPだった)。したらちゃんと投稿されていた。ふむ。ここで何を思いついたのか、「wordpress xml パース」と昨日みたいなことを検索した。simpleXML?というライブラリがあるらしかったので、それを試してみることにした。(たぶんPHPが動いたので気をよくしてたんだと思う)
こういう流れでいけると思った。考え方はactionscriptをエディタに書いて、ノリであてにいった。変数に宣言するのはできた。$var1とかで宣言したことになるらしい。URLRequestに相当するコードを探したら「file_get_contents」らしいことが分かった。(「PHP 外部ファイル」で検索)
で、ゲットしたのはXMLなんだけど、上記検索したなかにたまたま書いてあった「simplexml_load_string」というのを使うとXMLをパースできそうな気がしたので、ノリで書いたactionscriptでは
var req:String = "http://search.twitter.com/?q.atom=mogemoge";
var r:URLRequest = new URLRequest(req);
var kekka:XML = r.send() as XML; ←いまここ
なので、XMLにキャストしたんだろうなみたいな感じだった。E4Xを使えればいいのにPHPって馬鹿ねと思いながら寝た。
年があけて、3が日が終わりそうだった。年末にやってたこと(上記までのこと)を思い出しながら、XMLの必要な部分だけ抜き出す方法を模索した。atomっていってもentryがたくさん入ってたから配列にするんだろうけど、ってんで「php foreach」を検索。なんとなくサンプルコードをまねしながら、記事タイトル、記事本文だけ取得した。あとはxmlrpcのサンプルにあわせて投稿するようにした。できた。寝た。
次の日の朝、ブログを見た。昨日更新したものしかあがってない。自動じゃねーじゃん。
で、「自動 投稿」で検索したら、クローン(cron)という仕組みを使わないといけないのだった。クローンはサーバの仕組みらしく、そういえば俺はPHPをはじめDB、サーバという単語を極力さけて仕事してきたので、もう気持ちが悪くなってきた。「さくらインターネット cron php」で検索して、なんとかやり方を見つけて、cronを登録した。(1時間に1回にした。設定は * * * 0)
仕事から帰ってきて、サイトを見ると、投稿が大量にたまっていた。やった!で、調子に乗ってツイッターアカウントを作った。なんだったらツイッターも自動化したかったので「twitter bot」で検索した。Easybotterというサンプルボットがあったので使わせてもらった。自動で一行ずつつぶやくようにした。
ツイートを集めることは成功したけど(毎時間100件のツイートを1エントリとして投稿してる)、それを眺めて面白いんだろうか? ボットを動かしてるけど人がくるんだろうか?
そんなとき「trivist」がはてブに載ってた。なんかにたものを感じた。やっぱツイートを引っ張ってきて投稿するサイトはアリなのか?アリなはずだ!
サイトの体裁を整えた
trivistをまねて、記事を評価(はてなスターとかいいねボタンとかに近いもの)する仕組みが欲しくなった。「wordpress 評価 プラグイン」で「wp-postratings」というプラグインを発見して、入れてみた。どうやら1エントリーに1評価しかできないらしい。俺のサイトは1エントリーに100ツイートあるから、どのツイートを評価するのかが分からない。
いったん、wordpressの全投稿を削除した。で、cron に登録されてるPHPを、1記事に1エントリーにした。
エントリーを投稿するついでに、Yahoo日本語解析APIをつかってツイートを分析して、名詞と動詞だけを取り出そうと思った。それをタグにすれば、タグクラウドが作れると思った。はてブはずっとずっと昔からやってるから、Yahoo日本語解析っていうのが2006年くらいに流行ったことをなぜか憶えてたので、やってみた。できた。
なんか俺、PHP書くのが早くなってね?
アクセス解析を入れてみた。サイトに来てる人は、俺だけだった。
どうにかして人を増やしたい。サイトの広告募集はする気がないし、ベタベタとバナーを貼りたくなかった。みんなが気軽に見に来て、軽い気持ちで評価してくれて、更新を楽しみにしてくれるサイトにしたかった。コミュニティサイトじゃないけど、やっぱりサイトはコミュニケーション設計をしないと意味がないんじゃないか、見てくれるユーザはどうやったら楽しいんだろう、ということを考え続けて10日ほど経った。Twitter経由で来てくれた人が3人ほどいるようだけど、何がダメなのか分からないので増田にお願い。
ここまで書いて教えてくんじゃねーか、と思われるかもしれないが、ググレカス的な検索は上記で書いたみたいにいろいろやってきた。でも、サイトを作ってみてはじめて、ユーザに向けたサイトってどう作ればいいのかが分からないということに気づいた。
小遣い稼ぎもしたいんだけど、面白いサイトを作るヒントがほしいと思った。
kanzen21やtrivistみたいに、俺も過程を全部さらしたから、辛辣な意見を求む。そしてはてブされるのを待ってます。
http://okajima.air-nifty.com/b/2010/01/post-abc6.html
迷路の最短経路を求める問題が出たので解いてみた
幅優先探索を使えばいいのがわかっていたのですんなりかけたのだが、無限ループになる個所があったので動くようになるまで時間がかかった
using System; using System.Collections.Generic; using System.Text; using System.Linq; namespace MazeFind { class Point { public int x; public int y; public Point before; public Point(int x, int y,Point before) { this.x = x; this.y = y; this.before = before; } } class Program { static void Main(string[] args) { const char BreakChar = 'B'; const char GoalChar = 'G'; const char WallChar = '*'; const char BeforeChar = '.'; StringBuilder[] maze = new StringBuilder[]{ new StringBuilder("**************************"), new StringBuilder("*S* * *"), new StringBuilder("* * * * ************* *"), new StringBuilder("* * * ************ *"), new StringBuilder("* * *"), new StringBuilder("************** ***********"), new StringBuilder("* *"), new StringBuilder("** ***********************"), new StringBuilder("* * G *"), new StringBuilder("* * *********** * *"), new StringBuilder("* * ******* * *"), new StringBuilder("* * *"), new StringBuilder("**************************"), }; Point start = new Point(1, 1,null); //最短経路を探索する Queue<Point> queque = new Queue<Point>(); queque.Enqueue(start); while (queque.Count > 0) { Point now = queque.Dequeue(); if (maze[now.y][now.x] == BreakChar) Console.WriteLine("break"); if (maze[now.y][now.x] == WallChar || maze[now.y][now.x] == BeforeChar) continue; else if (maze[now.y][now.x] == GoalChar) { Point p = now.before; while (p != null) { maze[p.y][p.x] = '@'; p = p.before; } break; } if (maze[now.y - 1][now.x] != '#') { queque.Enqueue(new Point(now.x, now.y - 1, now)); maze[now.y][now.x] = '.'; } if (maze[now.y][now.x + 1] != '#') { queque.Enqueue(new Point(now.x + 1, now.y, now)); maze[now.y][now.x] = '.'; } if (maze[now.y + 1][now.x] != '#') { queque.Enqueue(new Point(now.x, now.y + 1, now)); maze[now.y][now.x] = '.'; } if (maze[now.y][now.x - 1] != '#') { queque.Enqueue(new Point(now.x - 1, now.y, now)); maze[now.y][now.x] = '.'; } } //結果を出力する foreach (StringBuilder s in maze) Console.WriteLine(s.ToString().Replace(BeforeChar,' ')); Console.ReadLine(); } } } <||
最近は、24インチ 30インチディスプレイなんて安いんだから、横80ではなく横120ぐらいは平気で使える。
classname::enumname という毎回指定でも エディタがインテリジェントに保管してくれるから問題ない。
基本的に 外部ツールがチェックしてくれるんだから
enum{
{
};
で問題ないと思われ
言い方を変えれば、class内部以外でenumを定義することなんて最近はあるのか?グローバルなenumなんて余り無いと思うが・・・
クラス内部では、省略できるし、外部から、クラス内部の値を呼ぶときは、どのクラスのこのenumって外部だよって意味で毎回書いたほうが安全だろ?
using namespace std
ですら、書かないほうが安全 毎回std::って書かないと、うっかり、stringクラスを定義する人がいないとは限らんからね・・・
一斉に変更したい? エディタに正規表現で置換すればよろしい・・・
原則、外部のツールで解決できる問題は、外部のツールで解決すればいい。
言語仕様を拡張されると、初心者に、その理屈を説明するという問題が出てきて、そういうのは初心者には無理。
他方、ツールを使えない初心者でも、毎回コピペや手で置換は出来る。
オブジェクトのシリアライズツールであるプロトコルバッファについて書きます。
Protocol Buffers 本家
http://code.google.com/apis/protocolbuffers/
XMLはもう不要!? Google製シリアライズツール「Protocol Buffer」
http://journal.mycom.co.jp/articles/2008/07/18/protocolbuffer/index.html
Protocol Buffers (Protocol Buffers の内部解説記事。とても参考になります)
http://dodgson.org/omo/t/?date=20080712
プロトコルバッファは異種言語間でオブジェクトのやりとりをするための規格です。
独自の言語によりオブジェクトのインターフェースを規定することで、多言語対応を行っています。
例えばこんな感じ。
package tutorial; message Person { required string name = 1; required int32 id = 2; // Unique ID number for this person. optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { required string number = 1; optional PhoneType type = 2 [default = HOME]; } repeated PhoneNumber phone = 4; } // Our address book file is just one of these. message AddressBook { repeated Person person = 1; }
以上のようなprotoファイルから各言語のソースコード、または何らかのデータ操作ライブラリを使いオブジェクトの処理を行います。
googleによってC++, Java, Python用のライブラリが作成されましたが、他の言語に対応したサードパーティー製のライブラリがいくらでもあるので、実質的にほぼすべての言語で使えると言っても過言ではありません。
数字が多きければ大きいほど、長いバイト長で保存されます。ただし、負数の場合は符号ビットが立つ関係で、ほとんど常に変換後のバイト数が最長バイト数(10)になってしまいます。フィールドの型をsint32, sint64で宣言しると、各数値にzig-zags変換が行われるため、負数であってもその値の絶対値で使用バイト数が決まるようになります。
バイナリに保存されるデータは各メッセージのID/型/値のみです。なので、同じ定義の二つのメッセージ型は、プロトコルバッファ上では全く同じように扱うことが出来ます。例えば、片方からシリアライズしたデータを、もう片方の型でデシリアライズすることが可能です。
またオブジェクトを連続でシリアライズ/デシリアライズすることもできます。
すでに存在する継承関係のあるクラスを、Protocol Buffersでシリアライズ/デシリアライズしたい場合は次のようにします。
(ソースコード中になぜか日本語が書けないので、コメントはすべて英語になっています)
message PbBase { require int32 id = 1; require int32 value = 2; require Derived derived = 10; // - Point !!! } message PbDerived { require string string_value = 1; }
継承元のメッセージの定義に、継承先のメッセージを持たせます。Baseを継承するクラスをシリアライズ/デシリアライズしたい場合は、PbBaseメッセージを中心に処理を行うことで、比較的簡単に処理を実装することが出来ます。
例えばこんな感じ
Base *Base_DeserializeFrom(PbBase &amp;pbobj) { // Arrange the classes which inherits from Base. if (pbobj.has_derived()) { return new Derived(pbobj); } else ... } class Base { ... virtual void Base::SerializeTo(PbBase &amp;pbobj) { // Set the fields of 'pbobj', } ... }; class Derived { ... virtual void Base::SerializeTo(PbBase &amp;pbobj) { PbDerived *derived = pbobj.mutable_derived(); Base::SerializeTo(pbobj); // Set the fields of 'derived', ... } ... };
protoファイルを以下のように書くと、メッセージの扱いが非常に難しくなります。
message PbBase { require int32 id = 1; require int32 value = 2; } message PbDerived { required PbBase base = 1; // - Here is the point !!! require string string_value = 2; }
Rコンソールに一行ずつコマンドを入力してもいいけど、実際に使うにはテキストファイルにコマンドを書いて(ソースコード)一気に実行させる方が楽。
source('hogehoge.R')
hogehoge.Rというのがソースコードを書いたファイル(ソースファイル)の名前。
CRANという、CPANのパクリがある。膨大な数のライブラリがあるので、好きなものをインストールするには、
install.packages('hoge',dependencies=TRUE)
とするのが楽。
> あ<-1 > あ [1] 1
a<-1 b=2 1->a
どれでもいい。但し推奨されてるのは一番上。Rの人は「束縛」という言葉を使いたがる傾向があるけど、どっちでもいいと思う。
余談だけど、関数の引数の中で代入できる、しかもその値をそのあとの引数で使える。これ実は便利。
> sum(a<-1,a) [1] 2
> a [1] 1 > str(a) num 1 > summary(a) Min. 1st Qu. Median Mean 3rd Qu. Max. 1 1 1 1 1 1
最後のsummaryはRっぽい。strっていうのはstringではなくstructの略(だと思ってる)。Rの変数はいくらでも複雑な構造になり得るけど、そのときにぱっと見がわかるように構造を出力してくれる。
Rの基本はベクトル。
ベクトルの作り方はいくらでもあるけど、例示するのが早いでしょう。
> x<-1:3
> y<-c(TRUE, FALSE, TRUE)
> z<-c("a","b","c")
> x
[1] 1 2 3
> y
[1] TRUE FALSE TRUE
> z
[1] "a" "b" "c"
他にもいっぱいあるし、関数の返値がベクトルってこともよくある。
> runif(3) [1] 0.2200965 0.6391403 0.1089252
一様乱数を三個作った。
> x<-letters[1:5] > x [1] "a" "b" "c" "d" "e" > x[2] [1] "b" > x[4:5] [1] "d" "e" > x[c(1,3,5)] [1] "a" "c" "e"
こんな感じで、[]の中に添え字でアクセス。1-indexなので注意。2,3番目の例では添え字にもベクトルを使って、複数の要素に一気にアクセスしてる。
> x[3]<-"z" > x [1] "a" "b" "z" "d" "e"
でOK。
要望があれば続くかも。
http://anond.hatelabo.jp/20100119023114
しょぼい煽りだなあ。
煽りに見えるのかなあ。
そりゃそうですが。
よくできたアプリを公開している人は、定義からして優れたプログラマなわけですが、何も公開しない人は、優れたプログラマかどうかはわからない。
優れたプログラマがアプリを公開しているとは限らないですが、公開しない人が優れたプログラマであるとは限らない。
もちろん「優れたプログラマであるとは限らない」だけで、優れたプログラマではないと断定はできないですが、これだけの長期にわたってこれだけ大量のエントリを投下している割に、具体的な技術の話がさっぱりないのはかなり異様に見えます。
昔はコードを少し載せてた。
ちょっと見てみた。
http://d.hatena.ne.jp/JavaBlack/archive/200503
2005年の分をタイトルだけさらってみたけど、コードが載ってるのは上記のStringの結合ネタぐらいのような……もちろんこういう記事はJavaプログラマにとっては(中級異常のプログラマには常識の範疇とはいえ)かなり役に立つ記事だと思うんですよ。でも、その後そういう記事は減少の一方じゃないですか?
このリストはJavaやる人なら必須でしょ。このリストを作ってくれてるだけでブログレベルでは十分だと思う。
Java&オブジェクト指向参考書リスト(2007年版)http://d.hatena.ne.jp/JavaBlack/20070522/p1
普通のブログ記事として、この記事だけを見たら、悪くないエントリだと思う。
でも、逆に言うとどれも標準的な必読書。内容に関する言及もないので、それこそ本をまったく読まなくても、ネットで評判を調べるだけでこのリストは作れそうだ(JavaBlack氏がこれらの本を読んでないと言っているわけじゃない。邦訳ぐらいは読んでると思う)。
でもさ、普段あれだけ上から目線の偉そうなエントリを連投している割には、ご本人の技術力は、さっぱり具体的には見えてこない。
ブコメだと、(今回の地震の話はさておき)そこそこ好意的なコメントが付くようだけど、そのへんみんなどう思ってるのかな、と思ったわけですよ。
全能感を維持するために「なにもしない」人達
http://d.hatena.ne.jp/p_shirokuma/20100119/p1
JavaBlack氏は、自らの全能感を維持するために、コードを書いたり公開したりしないのかな、という気もちょっとする。
実力を晒さない限りは、馬鹿にされることもないからね。
ええと、ご本人がこれを見ることがあるとしたら、
と言いたいです。JavaBlack氏がまだ求職中なのかどうか知らないけど、もし私がうちの会社の人事権を持っていたとしても、悪いがこの人は採らない。
34分
現役のときに比べて腕が鈍ってるなあ
ソースは汚いよ
同じところを二回訪れないことに注意して、次の状態をキューに入れていけばいいだけ
隣は距離1なのでただのFIFOでいい
重み付きのグラフならpriority queueを使う
dequeなんちゃらの前までが入力で、while の中が重要なコード
答えはSとGも塗り潰しちゃったのを出力してる
サンプルの入力で最短距離であることを確認してる
#include <map> #include <string> #include <iostream> #include <vector> #include <iterator> #include <deque> #include <set> using namespace std; typedef pair<int, int> P; int dir_x[] = {0,1, -1, 0}; int dir_y[] = {1, 0, 0, -1}; int main() { string line; vector<string> input; while (getline(cin, line)) { input.push_back(line); } const int X = input.size(); const int Y = input.begin()->size(); vector<P> start; P goal; for (int i = 0; i < X; i++) { for (int j = 0; j < Y; j++) { if (input[i][j] == 'S') { start.push_back(P(i, j)); } else if (input[i][j] == 'G') { goal = P(i, j); } } } deque<vector<P> > Q; set<P> visited; Q.push_back(start); while (!Q.empty()) { vector<P> p = Q.front(); Q.pop_front(); if (visited.find(p.back()) != visited.end()) { continue; } visited.insert(p.back()); if (p.back() == goal) { for (int i = 0; i < p.size(); i++) { input[p[i].first][p[i].second] = '$'; } copy(input.begin(), input.end(), ostream_iterator<string>(cout, "\n")); break; } for (int i = 0; i < 4; i++) { P next = P(p.back().first + dir_x[i], p.back().second + dir_y[i]); if (input[next.first][next.second] == '*') { continue; } vector<P> new_state(p.begin(), p.end()); new_state.push_back(next); Q.push_back(new_state); } } return 0; }
これで40分。
タイムアタックってことでアルゴリズムは全幅探索で書き上げました。
エラーチェック皆無。
A*ならもう5分ほど延びるかな?
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace Maze { class Program { // 探索用地図 static int[,] maze; // 始点終点 static Position Start = new Position(0, 0), Goal = new Position(0, 0); static void Main(string[] args) { //////////////////////////// まずは各行のリストとして読み込み string[] inMaze; using (var fp = new FileStream(args[0], FileMode.Open, FileAccess.Read)) using (var iStream = new StreamReader(fp)) inMaze = iStream.ReadToEnd().Split('\n'); // 迷路幅 int height = inMaze.Length; // 迷路高さ int width = inMaze[0].Length; /////////////////////////// 読み込んだ迷路を作業用地図に展開 maze = new int[width, height]; for (int y = 0; y < height; ++y) { string line = inMaze[y]; for (int x = 0; x < line.Length; ++x) { maze[x, y] = line[x] == '*' ? -1 : 0; if (line[x] == 'S') Start = new Position(x, y); if (line[x] == 'G') Goal = new Position(x, y); } } // 探索実行 int dist = Search(maze, Start); // 探索結果から最短経路を再現 Position backTracer = Goal; while (dist>1){ --dist; backTracer = backTracer.Nearbys.First(pos => maze[pos.X,pos.Y] == dist); maze[backTracer.X, backTracer.Y] = -2; } //////////////////// 最短経路こみのアスキー地図に変換 char[,] outMaze = new char[width, height]; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { outMaze[x, y] = maze[x, y] == -2 ? '$' : maze[x, y] == -1 ? '*' : ' '; } } outMaze[Start.X, Start.Y] = 'S'; outMaze[Goal.X, Goal.Y] = 'G'; ////////////////////// 結果は標準出力に。 for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) Console.Write(outMaze[x, y]); Console.WriteLine(); } Console.ReadLine(); } /// <summary> /// 探索する。SG間の道のりを返す(道のり=SGが隣接しているなら1) /// </summary> private static int Search(int[,] maze, Position Start) { List<Position> FrontLine = new List<Position>(); FrontLine.Add(Start); int dist = 1; for (; ; ) { List<Position> NextFrontLine = new List<Position>(); foreach (var pos in FrontLine) { foreach (var nextPos in pos.Nearbys) { if (nextPos == Goal) return dist; if (maze[nextPos.X, nextPos.Y] == 0) { maze[nextPos.X, nextPos.Y] = dist; NextFrontLine.Add(nextPos); } } } FrontLine = NextFrontLine; ++dist; } } } struct Position { public readonly int X, Y; public Position(int x, int y) { X = x; Y = y; } public IEnumerable<Position> Nearbys { get { return new[]{ new Position(X-1,Y), new Position(X,Y-1), new Position(X+1,Y), new Position(X,Y+1), }; } } public static bool operator==(Position p1, Position p2){ return p1.X == p2.X && p1.Y == p2.Y; } public static bool operator!=(Position p1, Position p2){ return p1.X != p2.X || p1.Y != p2.Y; } } }
10/18 改訂
なお、取得した画像の著作権はグーグル他各社が保持しています。
ご利用は計画的に私的範囲でどうぞご利用ください。
#!/usr/bin/perl use strict; use warnings; use Getopt::Long; use LWP::UserAgent; use GD; my $cmdline = join(" ", $0, @ARGV); my $usage = "usage: $0 -sx=116423 -sy=51603 -ex=116426 -ey=51605 -dx=4 -dy=3 -z=17 -size=300 -get=30 -dir=cache -output=output.jpg -nodebug"; my ($sx, $sy) = (0, 0); my ($ex, $ey) = (0, 0); my ($dx, $dy) = (4, 3); my $z = 17; my $size = 300; my $get = 30; my $dir = "cache"; my $output = "output.jpg"; my $debug = 0; GetOptions("sx=i" => \$sx, "sy=i" => \$sy, "ex=i" => \$ex, "ey=i" => \$ey, "dx=i" => \$dx, "dy=i" => \$dy, "z=i" => \$z, "size=i" => \$size, "get=i" => $get, "dir=s" => \$dir, "output=s" => \$output, "debug!" => \$debug) or die "$usage\nDied"; if ($ex == 0) { $ex = $sx + $dx; } else { $ex++; $dx = $ex - $sx; } if ($ey == 0) { $ey = $sy + $dy; } else { $ey++; $dy = $ey - $sy; } $sx>0 and $dx>0 and $sy>0 and $dy>0 and $z>0 and $dir and $output or die "$usage\nBad arguments"; $dx*$dy > $size and die "Getting too large."; $debug and print "debug: mkdir $dir\n"; mkdir $dir; -d $dir or die "can't make dir $dir: $!"; my $base = sprintf("http://khm%d.google.co.jp/kh/v=46&z=%d", int(rand(4)), $z); my $ua = LWP::UserAgent->new; printf "now get %d images...\n", $dx*$dy; for (my $x=$sx; $x < $ex; $x++) { for (my $y=$sy; $y < $ey; $y++) { my $file = sprintf("%s/%02dz%06dx%06d.jpg", $dir, $z, $x, $y); $debug and print "debug: check of $file\n"; -s $file and next; --$get < 0 and last; my $req = HTTP::Request->new(GET=>+"$base&x=$x&y=$y"); $debug and print "debug: fetch from ".$req->uri."\n"; my $res = $ua->request($req); unless ($res->is_success) { print "fail fetch from $file: ", $res->status_line, "\n"; next; } if (open(my $fh, ">", $file)) { $debug and print "debug: write of $file\n"; binmode $fh; print $fh $res->content; close $fh; } else { print "fail open in $file: $!\n"; } } } $get < 0 and print "reach the getting limit, skip after all.\n"; printf "creating %dX%d image...\n", 256*$dx, 256*$dy; my $image = new GD::Image(256*$dx, 256*$dy); for (my $x=$sx; $x < $ex; $x++) { for (my $y=$sy; $y < $ey; $y++) { my $file = sprintf("%s/%02dz%06dx%06d.jpg", $dir, $z, $x, $y); $debug and print "debug: check of $file\n"; -s $file or next; $debug and print "debug: read of $file\n"; my $part = GD::Image->newFromJpeg($file); $debug and print "debug: image copy\n"; $image->copy($part, 256*($x-$sx), 256*($y-$sy), 0, 0, 256, 256); } } #$image->string(gdSmallFont, 0, 0, $cmdline, $image->colorAllocate(255, 255, 255)); open(my $fh, ">", $output) or die "fail open $output: $!"; $debug and print "debug: write of $output\n"; binmode $fh; print $fh $image->jpeg(); close $fh;
例えば秋葉原とか
perl gmwall.pl -sx=116423 -sy=51603 -ex=116427 -ey=51606
駅だけとか
perl gmwall.pl -sx=465701 -sy=206420 -ex=465705 -ey=206423 -z=19
使う数値はfirebugなどで拾ってください。
class FizzBuzzProgram{ public static void main(String args[]){ for (int i = 0; i++ < 100; ) { System.out.println(new Number(i).checkMod3().checkMod5()); } } } interface Mod3Mod5Unchecked extends Mod5Unchecked { public Mod5Unchecked checkMod3(); } interface Mod5Unchecked { public Object checkMod5(); } class Number implements Mod3Mod5Unchecked{ private int no; public Number (int no) { this.no = no; } public Mod5Unchecked checkMod3() { return no % 3 == 0 ? new Fizz(no) : this; } public Object checkMod5() { return no % 5 == 0 ? new Buzz() : this; } public String toString() { return Integer.toString(no); } } class Fizz implements Mod5Unchecked{ private int no; public Fizz (int no) { this.no = no; } public Object checkMod5() { return no % 5 == 0 ? new FizzBuzz() : this; } public String toString() { return "Fizz"; } } class Buzz { public String toString() { return "Buzz"; } } class FizzBuzz { public String toString() { return "FizzBuzz"; } }