phpのpreg_replace_callbackをc#で書くと・・・ #php #csharp #memo

PHPにpreg_replace_callbackという関数があります。

正規表現検索を行い、コールバック関数を使用して置換を行う
http://php.net/manual/ja/function.preg-replace-callback.php

というものです。

これをC#でやるときは、

System.Text.RegularExpressions.Regex.Replace メソッド (String, String, MatchEvaluator)
http://msdn.microsoft.com/ja-jp/library/ht1sxswy.aspx

を利用します。

第1引数が入力文字列で、
第2引数が検索のための正規表現文字列です。
第3引数のMatchEvaluatorデリゲートの中でマッチした部分文字列に対して置換処理を行います。

preg_replace_callbackのマニュアルページの例2にあるサンプルコードをcsで表すとすると以下のようになります。
参考までにPHP側のコードを冒頭にコメントで乗っけています

Regex.Replaceメソッドの使い方のほんの一例です(そもそもreplaceメソッドのオーバーロードの一つでしかない。
ので、詳細は上記MSDNで確認してください。

//  <?php
//// このテキストは 2002 に使われていたものなのですが、
//// これを 2003 年対応の日付に変更したいのです
//$text = "エイプリルフールの日付は 04/01/2002 ですn";  
//$text.= "この前のクリスマスの日付は 12/24/2001 でしたn";  
//// コールバック関数
//function next_year($matches)
//{
//  // 通常は、$matches&#91;0&#93; がマッチした全体を表します。
//  // $matches&#91;1&#93; は、マッチした中で、パターン内の最初の '(...)'
//  // にあてはまる部分を表します。それ以降も同様です。
//  return $matches&#91;1&#93;.($matches&#91;2&#93;+1);
//}
//echo preg_replace_callback(
//            "|(d{2}/d{2}/)(d{4})|",
//            "next_year",
//            $text);

//?>

            var text = @"エイプリルフールの日付は 04/01/2002 です
この前のクリスマスの日付は 12/24/2001 でした";

            
            var replacedText = Regex.Replace(
                 text,
                @"(d{2}/d{2}/)(d{4})",
                //x.Valueおよびx.Groups[0]で部分文字列全体
                //x.Groups[1以降]は上記席表現の()で括られた部分にあたる部分文字列
                 x =>
                 {
                     return x.Groups[1].Value + (Convert.ToInt32(x.Groups[2].Value) + 1);
                 });

            Console.WriteLine(replacedText);

余談ですが、VS2013を使って、debug中にunhandledな例外が発生した時ローカル変数用のウォッチウィンドウに$exceptionという名前で例外情報が表示されるのが地味に良いと思いました。

FacebookTwitterHatenaTumblr共有

Windows 8でMicrosoftアカウントと関連付けたアカウントにUnityをインストールして起動したい時 #unity

Windows 8にUnityやVirtualBoxをインストールして起動したい時、Microsoftアカウントと関連付けて日本語名で作成したアカウントだと起動に失敗します。
それでもMicrosoftアカウントと関連付けしたい時は以下の手順で

Step1.アルファベットでローカルアカウントを作成
Step2.ユーザの設定変更でMicrosoftアカウントと関連付けを行う
Step3.Unityなどをインストールする。

Step2とStep3はどちらが先でもOKです。
これで、起動に失敗することがなくなります。

VAIO Pro 13″を購入しました #物欲

VAIO Pro 13″を購入しました。
最後にVAIO X,P,Zを一気に手放してMacBook Air一色にしたのが2010年の11月なので、実に2年8か月くらいぶりにVAIOに戻ってきました。

ここ数年のVAIOのラインナップを見ると、どんどん軽量ハイパフォーマンスモデルがラインナップから消えていき(Zすら消えた)、他社はまるでVAIOのお株を奪うかのようにLavie ZやKIRAなど一部のスペックを除けば魅力的にうつる(でも買うまでには至らない)モデルが出てきていたので、もうVAIOの時代は終わってしまったのか、もうVAIOに惹かれることはないのかと思っていました。
(まぁ、初代VAIO Duoには惹かれましたが、11インチで1.4kgはちょっと辛いというところで・・・)

と油断していたところでいきなりVAIO Pro発売のニュースが飛び込んできました。
ちょうど、MacBook Airが発売されるタイミングだったので、その時は、とりあえず保留していましたが、新しいMacBook Airはバッテリの持ちが良くなった以外の大きなステップアップが無かったんですね(とはいえ、結構バッテリの持ちは大きい)。
それでも、MacならOSXとWindows両方動くしなー。でもFull HDのVAIO ProならUnityとか各種IDEなどが使いやすそうなど、逡巡していました。

そこで、いろいろブログを見て回っていたらとあるブログでMBAべた褒め、Windowsディス記事を見てしまい、基本、天邪鬼な自分としては、この出来事がVAIO Pro購入に至る最後のステップとなりSony Storeで速攻注文しました。
(その後、即納モデルが出たので、キャンセルして即納モデルに切り替えるなどしましたが・・・)

スペックはSSDが256GBであることを除いて他は最高スペックにしました。(MEM:8GB,CPU:Core i7-4500U,タッチパネル搭載)
タッチパネルは無しのモデルにしようかとも思った(120g軽くなるので)のですが、タッチパネル付きにして正解でした。
本日届いたばかりですが、あればあったで使いどころが案外あったりして・・・。

とりあえず、ファーストインプレッションとしては

・店頭モデルよりもキータッチがましになっていて、普通にタイプミスなく打てる
・液晶は綺麗だし、保護シート貼り付けサービスで保護シート張ってもらっていたので、液晶がアンチグレアな感じになっていてグレア特有の見づらさはないし
・13インチFullHDだとちょうどよいかもな細かさだし
・軽い!(13インチでMacBook Airの11と同じ重さ)とはいえ感動は無い。
・チョットファンが煩いかも。
・SSDが速いからなのか、何をするにも快適の一言。

と買ってよかったと思える一台でした。

ちなみに、外部出力がHDMIで、スペックシート上もFullHDまでと書いてあったのですが、事前4K出力できるという記事を見つけたので、もしかして自宅の27インチ(Dell U2711)にFullHDを超えた外部出力が出来るのではないかと思ってHDMI1.4ケーブルを購入したのですが、よくよく調べると自宅のU2711がHDMI1.3という残念な事態が発覚して今のところまだFullHD以上の出力が出来ていません。
U2713HMならHDMI1.4という話なので、どこかで試したい・・・と思っています。

とどうでもいいVAIO Pro 13″買ってよかったという記事でした。

転職してひと月経ちました

一ヶ月前にクルーズ株式会社を退職しました。

もともと、C#erだった私でしたが、クルーズで何をやっていたかというと、

JavaScriptベースのフレームワークを利用したiPhone/Android向けネイティブアプリ開発
C#を利用した社内システム開発チームのタスク管理及び、開発
PHPを利用した社内システム開発

などをやっていました。

ある程度好きにやらせてもらっていたので、特に不満があったわけでもなく、辞めたいと思ったことも全くありませんでした。

ではなぜ転職したのかというと、
好きな言語であるC#でもっと全力で開発できる環境があると知ってしまったからです。
そして、偶然、その環境と縁があったから。

というわけで、5月1日から株式会社グラニでC#と朝から晩まで向き合っている日々です。

今後は期待に応えられるよう本業で頑張りつつ、C#を中心としたエコシステムに、今まで以上にコミットしていけたらとおもいます。

SelectManyでreturn nullはご法度 #linq #csharp 訂正あり

久しぶりのブログということで、細かいことを少しだけ。

編集:指摘に合わせてサンプルコードを初出に比べて一部修正してあります。
6/2:nullで例外を返すサンプルがnullを返さなくなっていたので修正

LINQに実装されている拡張メソッドの一つにSelectMany
というものがあり作用としては、Selectと同じ作用+配列の平坦化を行なってくれるという活用しどころの多い拡張メソッドの一つです。

具体例としては以下の様なテストコードのような動作をします。
(Stringの配列の配列を平坦化してstringの配列にしてくれます。)
※テストコードはMSTest+Chainning Assertionを利用

        [TestMethod]
        public void TestMethod1()
        {
            var values = new[] { new string[] { "a", "b","c"},
                                 new string[] { "d" }, new string[] { "e" } };

            values.SelectMany(x => x).Is("a","b","c","d","e");               
        }

こっからが本題なのですがそのSelectManyの中のラムダでnullを返すとNullReferenceExceptionが発行されます。

先ほどの例をベースに配列の中に”b”が含まれている時はnullを返す実装例を示します。
※テストコード中では例外が投げられることを期待しているためcatch句に入ったら成功としています。

        [TestMethod]
        public void TestMethod2()
        {
            var values = new[] { new string[] { "a", "b","c"},
                                 new string[] { "d" }, new string[] { "e" } };

            try
            {
                //SelectManyでnullをリターンすると落ちるはず。
                var outputValues = values.SelectMany(x => x.Contains("b") ? null : x).ToArray();
            }
            catch (Exception ex)
            {
                Assert.IsTrue(true);   
            }

        }

上記のような実装をした時、nullがreturnされるタイミングでNullReferenceExceptionが発行されます。

ので、上記のような要件の時は、以下のようにそもそも対象外のものを事前に除外しておくか、

        [TestMethod]
        public void TestMethod3()
        {
            var values = new[] { new string[] { "a", "b","c"},
                                 new string[] { "d" }, new string[] { "e" } };

            values.Where(x => !x.Contains("b")).SelectMany(x => x).Is( "d", "e" );
        }

以下のようにnew string[]{}を返すかする必要があります。

        [TestMethod]
        public void TestMethod4()
        {
            var values = new[] { new string[] { "a", "b","c"},
                                 new string[] { "d" }, new string[] { "e" } };

            values.SelectMany(x => x.Contains("b") ? Enumerable.Empty<string>():x).Is( "d", "e");
        }

まぁどちらかといえば、可能なら事前に除外しておくのが正しいと思います。

Logicool Utltrathin Keyboard miniが届いたのでいろいろ試して見た

AppleStoreで注文しておいたLogicool Ultrathin Keyboard miniが届いたので試して見た結果をバラバラと記述してみる。

ちなみに検証としてさくらのVPSにPHP、MySQL、WordPressをインストールしてみた。

まずは、キーピッチについて。
アルファベットにあたる部分については全く問題を感じないレベルで快適に入力できる。
しかし、そのしわ寄せとして特殊キーが細長くなっている点や、Esc、TabがFnキーとの組み合わせでしか使えなかったりといったデメリットがある。
インストール作業はsshで行ったのだが上記のキーを比較的多用する作業なので、慣れるまでは大変。特にEscはホームキーに割り当てられているのでうっかりFn押さないで押しちゃうとsshアプリを閉じてしまう(もちろん切断はされないが・・・)のでめんどくさいことに。
パスを補完するときにTabキーを使うのだけどこちらはqに割り当てられているので、うっかりQQQQQとなることが何度かあった。

まぁ、でも概ね快適に入力できる。

キータッチはフニャっとはしてなくて比較的悪くない。薄くて軽い割に検討しているのではないか。

一番不満があるのは、iPad miniを載せる溝の角度が急なため、実際に利用する時に結構画面が見づらい状況になっている点である。
かなり上から見下ろすかたちになるので、もう少し斜めになっていた方がありがたかった。

用途として、文章入力には普通に実用的なレベルで入力ができるキーボードだが、コマンド入力したりviでスクリプト書いたりとかは、まぁ、なんとか使えるかなというレベルである。

とりあえず、買ってよかったかどうかと言われたら、良かったと答えられるレベルの製品で安心した。

#php 向け #LINQ もどきArrayWrapper for PHPでleft joinとjoinキーにラムダを設定できるようにした

ArrayWrapper for PHPで今まではJOINのキーには連想配列のキー名を指定するだけしかできませんでしたが、ラムダ式を渡せるようになりました。
これによって、指定したキーの値が連想配列だった場合など、さらに深い項目をキーに指定したり、加工した結果をキーに指定したりすることができるようになりました。
また、INNER JOINのみ対応していましたが、LEFT JOINにも対応することでJOINの活用の幅が広がりました。

ArrayWrapper for PHP

まず最初に、ラムダ式が指定できるようになった説明から・・・
今までは、

       $leftArray = array(
                    array("key" => 2,"name" => "Nasal Hair Cutter"),
                    array("key" => 3,"name" => "scissors"),
                    array("key" => 5,"name" => "knife")   
                );

        $rightArray = array(
                array("id" => 1,"item_id" => 2,"value" => 10),
                array("id" => 2,"item_id" => 2,"value" => 20),
                array("id" => 3,"item_id" => 2,"value" => 30),
                array("id" => 4,"item_id" => 3,"value" => 40),
                array("id" => 5,"item_id" => 3,"value" => 50),
                array("id" => 6,"item_id" => 5,"value" => 60),
                array("id" => 7,"item_id" => 5,"value" => 70),
            );

という配列に対して

//joinの引数は
//Join対象の配列,
//元の配列のキー一覧,
//join対象のキー一覧,
//joinした結果を表すmap関数,
//INNER JOINかLEFT JOINかを規定する
//となっている。
        $actual = ArrayWrapper::Wrap($leftArray)
                ->join($rightArray,
                        array("key"),
                        array("item_id"),
                        function ($leftValue,$rightValue)
                        {

                            return 
                                array("item_id" => $rightValue["item_id"],
                                         "name" => $leftValue["name"],
                                         "value" => $rightValue["value"]);
                        })
                ->toVar();

とキー指定のところに注目すると

array("key"),
                        array("item_id"),

と書いていましたが、キーにラムダ式を入れられるようになったので、

       $target = ArrayWrapper::Wrap($leftArray);

        $actual = $target
                ->join($rightArray,
                        array("key"),
                        array(function($x){return $x["item_id"];}),
                        function ($leftValue,$rightValue)
                        {

                            return 
                                array("item_id" => $rightValue["item_id"],
                                         "name" => $leftValue["name"],
                                         "value" => $rightValue["value"]);
                        })
                ->toVar();

array("key"),
                        array(function($x){return $x["item_id"];}),

のようにJOINするためのKEYの一覧に”function($x){return $x[“item_id”];}”というようなラムダも渡せるようになりました。
この機能、今みたいな配列の直近のIndexで解決できるものは、全然嬉しくないんですが、
“function($x){return $x[“a”][“b”];}”みたいに、何段か下の値を持ってきたい場合や、ある程度丸めて比較したい場合なんかに効果を発揮します。(実際に使っていてかなりの効果を得られています。)

次にLEFT JOINの説明です。

以下のように、Joinの最後の引数にJoinType::LEFTと渡してあげることで、left joinになります。

       $target = ArrayWrapper::Wrap($leftArray);

        $actual = $target
                ->join($rightArray,
                        array("key"),
                        array("item_id"),
                        function ($leftValue,$rightValue)
                        {

                            return 
                                array("item_id" => $leftValue["key"],
                                         "name" => $leftValue["name"],
                                         "value" => isset($rightValue) ? $rightValue["value"]:0);
                        },JoinType::LEFT)
                ->toVar();

#PHPで#LINQっぽい事ができるWrapperを作ってみた

LAMPな会社に来て1年半がたち、1ヶ月前にPHPデビューをしました。
で、やっぱりいろいろツライところがあったのと、風呂あがりに思い立ったのと、いろいろと触発されたところあって、PHPでLINQっぽく配列操作ができるWrapperを作ってみました。
実際に、最近恩恵に預かっているので作ってよかったなと思っています。

基本的に、where,select,reduce,groupBy,orderBy,join,zip,sum,averageが出来るようになっています。
詳細は、githubの以下のサイトを見てもらえばいいと思いますが、比較的速度を気にするようにしているので、中で処理するときのループ回数が少なくなるように設計してあります。

toVar()および、reduce()で配列が戻ってきます。

groupBy,orderBy,join,zip,sum,averageなどは、実際には一回実行して、新しくArrayWrapperでWrapしていますが、それ以外はできるだけ1回のループで処理が行われるようになっています。

ArrayWrapper for PHP

例えば、whereしてselectしてその結果を更に(意味ないけど)whereしたものを返すような書き方は以下のように出来ます。
(テストコードまんま貼り付けですが、$expectedが実行した結果だと思ってください。

    $target = new ArrayWrapper(
            array(
                array("key" => 1,"value" => 10),
                array("key" => 2,"value" => 11),
                array("key" => 3,"value" => 12),
                array("key" => 4,"value" => 13),
                array("key" => 5,"value" => 14)
            )
        );
 
    $actual = $target
            ->where(function($x){return $x["key"] > 2;})
            ->select(function($x){return array("K" => $x["key"],"V" => $x["value"] * 2);})
            ->where(function($x){return $x["K"] > 3;})
            ->toVar();
 
    $expected = array(
            array("K" => 4,"V" => 26),
            array("K" => 5,"V" => 28)
            );
        

例えば、groupByなんかは以下のように書けるようになっています。

$target = new ArrayWrapper(
        array(
            array("id" => 2,"value" => 10),
            array("id" => 2,"value" => 11),
            array("id" => 3,"value" => 12),
            array("id" => 3,"value" => 13),
            array("id" => 5,"value" => 14)  
        )
    );
 
//toVarで配列に戻す。
$actual = $target
        ->groupBy(array("id"))
        ->toVar();
 
//で結果、こうなる
$expected = array(
        array("keys" => array("id" => 2),"values" => array(
            array("id" => 2,"value" => 10),
            array("id" => 2,"value" => 11)
            )),
        array("keys" => array("id" => 3),"values" => array(
            array("id" => 3,"value" => 12),
            array("id" => 3,"value" => 13),
            )),
        array("keys" => array("id" => 5),"values" => array(
            array("id" => 5,"value" => 14)  
            ))
        );

joinもこんなふうに書きます。

    $leftArray = array(
                array("key" => 2,"name" => "Nasal Hair Cutter"),
                array("key" => 3,"name" => "scissors"),
                array("key" => 5,"name" => "knife")
            );
 
    $rightArray = array(
            array("id" => 1,"item_id" => 2,"value" => 10),
            array("id" => 2,"item_id" => 2,"value" => 20),
            array("id" => 3,"item_id" => 2,"value" => 30),
            array("id" => 4,"item_id" => 3,"value" => 40),
            array("id" => 5,"item_id" => 3,"value" => 50),
            array("id" => 6,"item_id" => 5,"value" => 60),
            array("id" => 7,"item_id" => 5,"value" => 70),
        );
 
    $target = new ArrayWrapper($leftArray);
 
    $actual = $target
            ->join($rightArray,
                    array("key"),
                    array("item_id"),
                    function ($leftValue,$rightValue)
                    {
 
                        return
                            array("item_id" => $rightValue["item_id"],
                                 "name" => $leftValue["name"],
                                 "value" => $rightValue["value"]);
                    })
            ->toVar();
 
    $expected = array(
                array("item_id" => 2,"name" => "Nasal Hair Cutter","value" => 10),
                array("item_id" => 2,"name" => "Nasal Hair Cutter","value" => 20),
                array("item_id" => 2,"name" => "Nasal Hair Cutter","value" => 30),
                array("item_id" => 3,"name" => "scissors","value" => 40),
                array("item_id" => 3,"name" => "scissors","value" => 50),
                array("item_id" => 5,"name" => "knife","value" => 60),
                array("item_id" => 5,"name" => "knife","value" => 70),
            );       

実際に、業務で使っていますが、groupBy、sum,orderByあたりはかなり重宝しています。

新しいMacBook Airを買ってしまった

新しいMacBook Airを買ってしまった。
今回はAppleStoreで発売日に注文した。
11″ SSD 512GB MEM 8GB core i7
の一番上のモデル。

前回、「新しいMacBook Airを買ってしまった。」と書いたのが昨年の8月だったので、1年経っていないのか。

前回は13″を購入したのだが、

・11″+ACアダプタをセットにしても13″よりも軽い。
・本格的に使う時は結局家で27″ディスプレイに接続する。

の2点から11″を購入。

今まで、11″->13″->13″->11″と来ているので結構迷走しているのかもしれない。

ちなみに、MacBook Airにハードウェア的な魅力はあまり感じていない。
ならば、何故買うのかというと、OSXとWindowsが両方使える中では一番軽いから。

来年は、11″でもRetinaな静電式タッチパネルを搭載し、800gくらいになっているとうれしい。