URLアクセスしHTMLタグ内から先頭のimgタグを抽出する方法について
こんにちは、エンジニアのR.Nです。
今回のテクヤンは、
C#と正規表現を用いて、特定URLへアクセスし、
対象のタグを抽出する方法をご紹介致します。
まず、URLより、HTMLタグを抽出方法を、以下のサンプルで説明します。
HTMLタグ抽出
【HTMLタグ抽出サンプルコード】 using System.Net; string html = string.Empty; // HTML取得 using (WebClient wc = new WebClient()) { html = wc.DownloadString("http://mindfree.jp"); }
変数名:htmlに、指定したURLページのHTMLがすべて返ってきます。
この文字列から、正規表現を使いimgタグを抽出します。
HTMLタグ抽出+imgタグ抽出
【HTMLタグ抽出+imgタグ抽出サンプルコード】 using System.Net; using System.Text.RegularExpressions; string html = string.Empty; // HTML取得 using (WebClient wc = new WebClient()) { html = wc.DownloadString("http://mindfree.jp"); } // imgタグ取得 string img = "<img src=\"(?<text>.*?)\".*?>"; Regex reImage = new Regex(img, RegexOptions.IgnoreCase | RegexOptions.Singleline); for (Match m = reImage.Match(html); m.Success; m = m.NextMatch()) { string u = m.Groups["text"].Value; }
m.Groups["text"].Valueからimgタグのsrcの値だけを抽出します。
例)
imgタグ:<img src="/common/images/nav_freemind.png" alt="FREEMIND">
m.Groups["text"].Value:/common/images/nav_freemind.png
サイトで使用しているアイコン、
画像情報を簡単に抽出することができますね。
大阪てら子で「iPhoneのSafariで動くWebアプリ開発」を発表しました
こんにちは。
@coppieeeこと八木です。
6/19に行われた大阪てら子に参加しまして、そこで「iPhoneのSafariで動くWebアプリ開発」の発表を行いました。こういう勉強会で発表するのは初めてでしたので、結構緊張しました。
それから時間がたってしまいましたが、発表資料を共有しておきます。
発表した内容は、野球盤アプリ「Handy Stadium」を作成したに使用した技術の紹介です。
ちなみに今回作成したアプリの開発にてASCII.jsで連載を公開しているので、
もっと詳しく知りたいという方は読んでみてください!
http://ascii.jp/elem/000/000/608/608847/
http://ascii.jp/elem/000/000/614/614208/
Javaの参照について
こんにちは、M.Oです。
今回はJavaと参照の関係をお題とした内容を紹介したいと思います。
「Javaは、基本参照渡しです」
これはずいぶん前に私自身が勉強会で発した言葉です。
微妙に語弊が生じているのがお分かりでしょうか?
これと似たようなことに、
Javaにはポインタがない
ということもよく聞きます。
結構このように理解されている皆様が多いのではないでしょうか?
本当にそうか?と思いこれに関して少し調べてみました。
まず最初に結論を出します。
Javaはすべて値渡しです。
これで全てなんですが、
これだけでは一瞬で記事が終わってしまうので、少しサンプルソースを交えながら
説明しておきたいと思います。
言葉の整理
まず少し言葉の整理をしておきます。
http://d.hatena.ne.jp/bleis-tift/20090603/1244031097
で紹介されている言語仕様によると
・Javaでは参照は、ポインタを表す。
・参照型は、参照(ポインタ)を保持する変数の型
となるそうです。
言葉の定義を念頭に次へ進みたいと思います。
検証
さて、ではちょっとした検証を行ってみましょう。
今まで信じていた通り、Javaが参照渡しなら以下のことが実現できるはずです。
・メソッドなどで引数に渡した変数自身に対しての変更が、呼び出し元の変数自身にも反映される。
この命題を検証するために以下のサンプルソースを試してみます。
仮引数への変更が、実引数に反映されているのかを検証するサンプルです。
もう少し手順を詳しく言うと、
メソッドを呼び出し、渡した引数をメソッド内で操作、
その後呼び出し側の引数と比較して変更が反映されているかを検証します。
サンプルソース
public class Main { public static void main(String[] args) { Target t1 = new Target("t1"); //変更前のインスタンスの表示 System.out.println(t1.toString()); //メソッド内で別の引数を生成する change(t1); //変更後のインスタンスの表示 System.out.println(t1.toString()); } public static void change(Target t) { t = new Target("t3"); } } class Target { private String name; public Target(final String name) { this.name = name; } public String toString() { return this.name; } }
実行結果
実行結果 t1 t1
解説
予想とは反した結果になっているのがお分かりでしょうか?
参照を渡しているのでオブジェクトに対する変更が反映されているはずです。
しかし、変更は反映されていません。
つまり、冒頭でイメージしていた参照渡しではないことがわかります。
値渡しで考えてみる
ここで値渡しであるという仮定のもと考えてみます。
値渡しをされた時点で、別の参照型変数に生成したオブジェクトのアドレスが格納(コピー)されます。
それが関数呼び出しにより、別のブロックに生成され渡されます。
この辺は「スタックと関数呼び出し」で検索するといいかもしれません。
関数を呼び出したときは、メモリの中でどのような動作が行われているのかを把握することができれば、
今回の記事はほとんど当たり前のように感じると思います。
実際に、私もあまり意識していなかったのでこのように調査をして記事を執筆しているのですが。
実際の動作のイメージは以下のようになります。
この時点で、main内の参照型変数t1とメソッドの仮引数で使われている変数tは別物ということになります。
ここで注意してほしいのは、互いの変数が指し示しているオブジェクトは同じということです。
なので、オブジェクトが指しているメンバ変数の変更は反映されるということです。
これは今までの通りのイメージですよね。t1のインスタンスのフィールドの変更は、呼び出し元でも反映されます。
結論
冒頭にあった結論を繰り返しますが、
「Javaはすべて値渡しです」
検証の例は、参照型を値渡ししている、というとわかりやすいでしょうか?
うーん、当たり前のような気がしますがじっくりと考えてみると結構ややこしいですね。
ちなみに、Javaにはきちんとポインタとなる概念が存在しますので、ポインタがないという
のは間違いで、ポインタを意識する必要がない、といった方がいいのかもしれませんね。
少し調査が足りないので、時間があればもう少し詳しく掘り下げることができると思います。
最後に色々なサイトを参考にしましたので、掲載しておきます。
今回の調査において、参考にさせていただいたサイトです。
「予定は未定Blog版」
http://d.hatena.ne.jp/bleis-tift/20090603/1244031097
「超てきとーですから」
http://macbookshiro.blog51.fc2.com/blog-entry-35.html
おまけ
Javaの引数は、全て値渡しであるためにprimitive型はswapができません。
そこでprimitive型をRapperするクラスを自作し、無理やりswapしてみました。
以下はイメージ図です。
ソースコード
public class Main { public static void main(String[] args) { RapperInteger rix = new RapperInteger(1111); RapperInteger riy = new RapperInteger(2222); System.out.println("before"); System.out.println(rix.toString()); System.out.println(riy.toString()); //swap swap(rix, riy); System.out.println("after"); System.out.println(rix.toString()); System.out.println(riy.toString()); } //swapメソッド public static void swap (final RapperInteger riX, final RapperInteger riY) { int tmp = riX.getValue(); riX.setValue(riY.getValue()); riY.setValue(tmp); } } //プリミティブ型をswapするためのラッパークラス class RapperInteger { private int value; public RapperInteger(final int value) { this.value = value; } public String toString() { return Integer.toString(this.value); } public int getValue() { return this.value; } public void setValue(final int value) { this.value = value; } }
出力結果
before 1111 2222 after 2222 1111
解説
primitive型をラップするクラスを自作して、そのクラスにprimitiveを保持する。
swapメソッドでは、ラッパークラスが保持しているprimitiveを入れ替える。
これでかなりの遠回りですが、primitiveのswapが実現できました。
Canvasで描いた絵をFlashで保存する方法
こんにちは、八木です。
最近、node.jsやFacebooアプリ作成など、JavaScriptを触る機会があり、JavaScriptも結構使いこなせるようになってきました。
私が作成したモザイクアートアプリの「Profile Photo Mosaic」もJavaScriptとCanvasを使用しています。
Facebookにログイン | Facebook※Facebookアカウントが必要になります
Canvasを使用すればJavaScriptだけで、お絵かきアプリや画像の編集などが出来て、Flashで作成するのとはまた別の楽しさがありますね。
このアプリも開発当初はJavaScriptのみで作成しようかと考えていたのですが、Canvasはファイルの保存/アップロードがサポートされておらず、作成した画像をFacebookにアップロード出来ないという問題がありました。
対処として画像のアップロードのみをFlashで実装するという方法をとったのですが、今回はそのJavaScriptからFlashに渡すときの実装の仕方を紹介したいと思います。
まず、画像をアップロード/ダウンロードするためには、Canvasのデータから画像データを作成しないといけません。
Canvasのデータを取得するにはtoDataURL()というメソッドを使うのがよさそうです。
//javascript var canvas = document.getElementById('canvas'); console.log(canvas.toDataURL('image/png')); //出力 //data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAY...
toDataURL()を使えば、画像のデータを取得することが出来ます。この値は画像をBase64でエンコードしたテキストデータになります。
これをバイナリデータに変換しなければならないのですが、JavaScriptはバイナリデータを直接触ることはできず、他のものを使用しないといけません。
画像の生成の方法として、一つはtoDataURL()で変換したデータをサーバに投げてサーバサイドで画像データに変換するやり方、もうひとつはtoDataURL()で変換したデータをFlashに渡して、Flash側で画像データに変換するやり方があります。
「Profile Photo Mosaic」ではあまりサーバサイドで処理をさせたくなかったので、Flashで処理するようにしました。
Flashではバイナリデータを直接扱うことが出来、ファイルの保存/アップロード/ダウンロードも自由自在に出来ます。
CanvasとFlashの連携サンプル
Flash側にバイナリデータを渡す場合、JavaScriptとFlashを連携して処理する必要があります。
Canvasでおえかきして、それを保存するサンプルを作成したので、それを使って説明していきます。
マウスでドラッグして色を塗り、saveボタンでローカルに保存するだけのサンプルです。色を塗る領域はCanvasを使用して、saveボタンはFlashを使用しています。
以下がhtmlのコードになります。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>CanvasToFlash</title> </head> <body> <canvas width="300" height="300" id="canvas"></canvas> <div id="save"></div> <script src="js/swfobject.js" type="text/javascript"></script> <script src="js/main.js" type="text/javascript"></script> </body> </html>
Canvasがお絵かきの領域で、#saveがFlashのセーブボタンになります。セーブボタンはswfobjectを使用してswfを読み込んでいます。
CanvasとFlashとの連携はmain.jsで処理しています。
//main.js (function(){ var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var pressed = false; //マウスドラッグで色を塗る canvas.addEventListener('mousedown', function (e) { ctx.beginPath(); ctx.moveTo(e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop); pressed = true; }); window.addEventListener('mousemove', function (e) { if(pressed){ ctx.lineTo(e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop); ctx.stroke(); } }); window.addEventListener('mouseup', function (e) { ctx.lineTo(e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop); ctx.stroke(); pressed =false; }); var canvasToFlash = window.canvasToFlash= {}; //flash側から呼ばれるメソッド。 //dataURLを返す。 canvasToFlash.getDataURL = function(){ return canvas.toDataURL('image/png'); }; //呼び出すメソッド名をFlash側に渡す。 var flashvars = { getDataURL:'canvasToFlash.getDataURL' }; var params = { menu: 'false', scale: 'noScale', allowFullscreen: 'true', allowScriptAccess: 'always', bgcolor: '#FFFFFF', wmode: 'direct' }; //swfobjectでswf読み込み swfobject.embedSWF( 'CanvasToFlash.swf' 'save', '100', '30', '10.0.0', 'expressInstall.swf', flashvars, params ); })();
コードの上半分は、マウスの操作で色を塗る処理です。下半分がswfの読み込みと、flash側から呼ぶメソッドの定義になります。
JavaScriptからFlashに値を渡す場合は、flashvarsに渡したい値を入れることによって、Flash側から呼び出すことが出来ます。
次にFlash側(ActionScript3.0)の処理を見ていきましょう。
//Main.as package { import flash.display.Sprite; import flash.events.MouseEvent; import flash.external.ExternalInterface; import flash.net.FileReference; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.utils.ByteArray; import mx.utils.Base64Decoder; public class Main extends Sprite { public function Main():void { var saveButton:TextField = new TextField(); saveButton.border = true; saveButton.borderColor = 0xaaaaaa; saveButton.text = 'save'; saveButton.selectable = false; saveButton.autoSize = TextFieldAutoSize.LEFT; addChild(saveButton); buttonMode = true; var params:Object = loaderInfo.parameters; var getDataURL:String = params.getDataURL; ExternalInterface.call(send,'init'); addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void { var dataURL:String = ExternalInterface.call(getDataURL); if (dataURL == null) { throw new Error(dataURL); } var decoder:Base64Decoder = new Base64Decoder(); //'data:image/png;base64,iVBORw0K...'の「,」以降のデータを取得してそれをデコードする decoder.decode(dataURL.split(",")[1]); var bytes:ByteArray = decoder.flush(); var file:FileReference = new FileReference(); file.save(bytes, 'img.png'); }); } } }
flashvarsで設定した値は、loaderInfo.parametersの中に入っており、それを参照することによって値を取得することが出来ます。また、Flash側からJavaScriptの関数を呼び出す場合は、ExternalInterface.call()メソッドを使用することによって実現できます。例えば、ExternalInterface.call('alert','hello');でJavaScriptのalert('hello')が実行されて、ポップアップが表示されます。
今回の例では、ExternalInterface.call(getDataURL);で、JavaScriptで定義したcanvasToFlash.getDataURL()を呼んでいます。
さて、dataURLのテキスト形式からバイナリデータのByteArrayに変換する方法ですが、変換にはmx.utils.Base64Decoderクラスを使用します。このクラスは「flex_sdk/frameworks/libs/framework.swc」の中に定義されており、使用するにはコンパイラ設定のパスを通してあげる必要があります。
最後に、FileReferenceクラスを使用して、バイナリデータをローカルに保存しています。
C#のstructについて
Java言語でもともと開発していた私が、JavaとC#でユーザー定義の扱いが違う為、C#で開発している時にはまりそうな資料を見つけたのでここで紹介します。*1
Java では、ユーザ定義型は全て参照型で、C#のようにstructという値型が存在しません。
C# では、参照型も、値型でも作成できます。また、標準ライブラリの中に struct で定義されたものもあります。
ここでは、C#でstructで作成した場合の注意点と、参照渡しの方法を資料を元に簡単に説明します。
C#でのstructの扱い
C#のstructは、classと違い「値渡し」され、コピーして渡されます。
struct Point { public int RegistPoint; public Point( int x ) { this.RegistPoint = x; } }
static void Regist(Point p) { p.RegistPoint = 100; } static void Main() { Point p = new Point(1); Regist(p); Console.WriteLine(p.RegistPoint); // 1 }
Java開発者であれば、100が上書きされて、100が表示されると思ってしまいますが、
C#のstructの場合は、1が表示されます。
C#で参照渡しをする場合
C#でstructの参照渡しをする場合は、refを使用します。
struct Point { public int RegistPoint; public Point( int x ) { this.RegistPoint = x; } }
static void Regist(ref Point p) { p.RegistPoint = 100; } static void Main() { Point p = new Point(1); Regist(ref p); Console.WriteLine(p.RegistPoint); // 100 }
1を渡していますが、
初期設定値の、100が表示されるようになります。
このように、メソッドの仮引数と実引数の両方に ref をつけることで、参照渡しとなります。
C#でstruct(構造体)を使用する場合、値の扱いには注意が必要です。
中国ネットのボトルネック問題について
こんにちは、chujiangleiです。
最近、中国の大きなマーケットを求め、多くの企業が進出を狙っています。中国現地でネットを利用し、ビジネスを展開するケースも少なくないです。
その中にはネット回線の速度低下の原因で失敗したケースもあります。よく言われる原因は下記の4点があります。
1.最も重要な原因はネットワーク人口が多く、平均アクセス数が高いです。
2.ブロードバンド化の進捗が遅く、ADSLがネット接続のメインとなっています。
3.通信キャリアー間の回線が細く、クライアント端末の間の接続に影響します。
4.金盾(きんじゅん)というインターネット通信を検閲するシステムが存在すること。
中国では多くの場所でボトルネック問題が存在します。それも回線速度低下の一因となっています。
ここで、中国ネットのボトルネック問題について説明させていただきます。
海外接続のボトルネック問題
@thewomble_za さんがBingマップ+WiKi情報を利用して海底ケーブル分布図を提供してくれました。
ここで、海底ケーブルの分布を通して中国のボトルネック問題を少し話したいと思います。
まず、世界海底ケーブルは下記の図のように分布しております。
ネット接点を少し拡大してみるとー
赤い枠のところは中国と海外に繋がっている接点です。海外からのアクセスはこの4つの接点を経由して中国の内陸都市に接続していきます。
その現状により、ボトルネック問題は発生しております。イメージが湧かないかもしれませんが、
下記の図は日本中部だけのネット接点を示します。全部で9個あります。
日本の状況と比べると、中国のネット接点がかなり少ないことがわかりました。
中国のネット人口は4.57億人(CNNIC調査データ)です。ネット人口が多いのとネット接点不足との間に、ボトルネック問題が存在しております。
ここの問題を早く解決しないと、中国のサイトはだんだん遅くなってきます。
中国国内接続のボトルネック問題
CNNIC 調査データにより、中国の各都道府県のネット速度の現状がわかりました。
本調査は、各時間帯で国内の各都市から、国内の20サイトにサクセスするテストを行いました。中国全国の平均速度は100.9kb/sです。
北京、上海などの中心都市は意外と13位、31位の低い速度になっています。
その中、北京、上海では、ブロードバンド化が普及しています。すべて2M以上になりました。
なぜ、ブロードバンド化が普及しましたのに、回線速度が高くならないか。
CNNIC は回線速度低下の問題をめぐって北京、上海のIDCを調査しました。原因としてはサーバの設置場所に関係します。
近年、コストなどの問題を考えたうえで各会社のサーバを都市外のIDCに設置するケースが多くなりました。
下記図のように中心都市と周辺とのボトルネック問題は発生しております。
都市周辺のインフラ整備が改善しないと、回線速度低下の現状は変わらないです。
まとめ
本記事は、中国ネットのボトルネック問題について説明いたしました。
中国の現状では、様々なボトルネック問題が存在しています。解決までまだ時間がかかると思います。
現時点の対策としては、できるだけ中心都市の市内のIDCセンターを選ぶほうがいいと思います。
参考資料
海底ケーブル分布図
http://www.cablemap.info/
第1代中国ネットワーク構成図 - CERNET(教育機関を中心に)
http://www.nrc.tsinghua.edu.cn/7_english/Situation1.htm
次世代の中国ネットワーク構成図 - CNGI(進行中)
http://www.cstnet.cn/cngi.jsp?Type=jiegoutu
http://www.nrc.tsinghua.edu.cn/7_english/Situation3.htm
中国国内ネット速度調査の元記事(CNNIC)
http://research.cnnic.cn/html/1295604366d2571.html
中国のIDC事情について
http://www.impressrd.jp/idc/story/2007/01/05/130?page=0%2C0
JavaScriptのprototypeについて
JavaやC#と比べてJavaScriptという言語はクラスがないという点で大きく違います。構文はC言語ライクで似ているのですが、オブジェクト指向でサポートされているものが違い、JavaやC#ではクラスベースのオブジェクト指向、JavaScriptはプロトタイプベースのオブジェクト指向です。
JavaScriptにはクラスやインターフェイスはありません。オブジェクトの実装や、型の継承はプロトタイプというのを使用して実装されます。
プロトタイプを使えばクラスと同じような機能を実装できますが、書き方が少々複雑で、プロトタイプを使用して型の継承を実装しているコードはあまり見ないです。
元々、JavaScriptは動的型付け言語で、メソッドやプロパティを自由に拡張できるので、プロトタイプを使用する必要はあまりないです。
ただし、オブジェクトを拡張したいという場合プロトタイプを使用すると非常に簡単に実装できます。
prototypeを使用してメソッド追加
例えばArrayのインスタンスにisEmpty()というメソッドを追加する場合は以下のように実装します。
isEmpty()は配列が空の場合trueを返し、空でない場合falseを返します。
//isEmpty()の実装 Array.prototype.isEmpty = function(){ return this.length == 0; };
Array.prototypeにisEmptyというメソッドを追加しています。
関数の中で使われているthisは、Arrayのインスタンスを指しています。なのでthis.lengthは配列の長さということになります。
このように「オブジェクト.prototype.メソッド名 = 関数」という書き方でオブジェクトを拡張できます。
実際に使ってみましょう。
Array.prototype.isEmpty = function(){ return this.length == 0; }; var xs = []; var ys = [1,2,3]; console.log( xs.isEmpty());//true console.log( ys.isEmpty());//false
prototypeを使用しなくとも関数を宣言すれば同じ処理はできます。
var isEmpty = function(array){ return array.length == 0; }; var xs = []; var ys = [1,2,3]; console.log(isEmpty(xs));//true console.log(isEmpty(ys));//false
関数呼び出しはisEmpty(xs)という形ですが、プロトタイプを使用した場合はxs.isEmpty(xs)という形で呼び出します。
細かな実行の違いはありますが、基本的な動作は同じです。
関数かプロトタイプでの拡張かの実装方法を場面に合わせて適切なものを選択しましょう。
n回繰り返すtimes()を実装
Arrayと同様にNumberも拡張可能です。
n回繰り返す
Number.prototype.times = function(f){ for(var i=0;i<this;i++){ f(i); } };
thisは数値になります。
実行してみましょう。
Number.prototype.times = function(f){ for(var i=0;i<this;i++){ f(i); } }; var xs = []; (10).times(function(i){ xs.push(i); }); console.log(xs); // [0,1,2,3,4,5,6,7,8,9]
times()の引数に入れた関数を10回実行しています。
times()を呼び出す場合は数値を()で囲まないといけません。
囲まずに「10.times(****)」と実行すると、「.」が小数点と間違えて解釈されてエラーになります。
どのような動きになっているのかわかりづらいので、プロトタイプを使わずに、コードを分解してみましょう。
var times = function(count,f){ for(var i=0;i<count;i++){ f(i); } }; var xs = []; var g = function(i){ xs.push(i); }; times(10,g); console.log(xs);
さらに分解。
var xs = []; var count = 10; for(var i=0;i<count;i++){ xs.push(i); } console.log(xs);
xs.push()を10回繰り返して呼び出しているのがわかります。
配列をシャッフルするshuffle()を実装
配列の要素ををシャッフルして新しい配列を返すshuffle()を実装。
画像をランダムに表示する場合などに便利です。
Array.prototype.shuffle = function () { var xs = this.concat(); for (var i = 0; i < xs.length; i++) { var j = xs.length * Math.random() | 0; var xi = xs[i]; xs[i] = xs[j]; xs[j] = xi; } return xs; };
実行してみましょう。
var xs = [1,2,3,4,5,6,7,8,9]; console.log(xs.shuffle()); //[4,2,1,8,5,7,9,0,3,6] console.log(xs.shuffle()); //[1,2,0,6,9,7,3,5,8,4] console.log(xs.shuffle()); //[5,8,6,4,2,7,1,9,3,0]
prototypeを使用する際の注意点
このようにprotoypeを使えばオブジェクトを拡張することが可能です。
ただし、ライブラリを併用したり、複数人で開発する場合は、prototypeで追加したメソッドの名前が競合してしまう場合があるので、注意が必要です。