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という名前で例外情報が表示されるのが地味に良いと思いました。

Share

#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あたりはかなり重宝しています。

Share