カテゴリー
C#

C# で JSON 形式のデータを取得

C# で JSON 形式のデータを取得することが VS2010 + .NET Framework 4.0 で非常に簡単に実現できるようになりました。System.Web.Extensions.dll で提供されている JavaScriptSerializer クラスを利用するのが便利です。
(※ System.Web.Extensions.dll は参照を追加する必要があります。)

郵便番号変換サービスを利用して、早速、試してみました。郵便番号の住所を JSON 形式で取得するオプションを指定して、HTTP GET で結果を文字列として受け取ります。それを YubinResponse0 というクラスに逆シリアライズするために JavaScriptSerializer クラスの Deserialize を呼ぶだけです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;

namespace yubin7
{
    // https://www.northwind.mydns.jp/samples/webservice/getaddress/1230841/<option>/json/utf8
    // <option>
    // 0: [{"seq":1,"zip7":"123-0841","addr":"u6771u4eacu90fdu8db3u7acbu533au897fu65b0u4e95"}]
    // 2: [{"seq":1,"zip7":"123-0841","pref":"u6771u4eacu90fd","addr":"u8db3u7acbu533au897fu65b0u4e95"}]
    // 3: [{"seq":1,"zip7":"123-0841","pref":"u6771u4eacu90fd","city":"u8db3u7acbu533a","town":"u897fu65b0u4e95"}]
    //
    // See https://www.northwind.mydns.jp/samples/webservice/webapidoc.php for more info.

    public class YubinResponse0
    {
        public string seq { get; set; }
        public string zip7 { get; set; }
        public string addr { get; set; }
    }

    public class YubinResponse2
    {
        public string seq { get; set; }
        public string zip7 { get; set; }
        public string pref { get; set; }
        public string addr { get; set; }
    }

    public class YubinResponse3
    {
        public string seq { get; set; }
        public string zip7 { get; set; }
        public string pref { get; set; }
        public string city { get; set; }
        public string town { get; set; }
    }

    public class Yubin7
    {
        const string YUBIN_API = "https://www.northwind.mydns.jp/samples/webservice/getaddress/{0}/0/json/utf8";

        public Yubin7()
        {
        }

        public string getAddress(string yubinNo)
        {
            string uri = string.Format(YUBIN_API, yubinNo);
            string result = httpGet(uri, "");
            string addr = "";

            if (result != null && result.Length > 0)
            {

                try
                {
                    // JSON 形式データを変換
                    JavaScriptSerializer ser = new JavaScriptSerializer();
                    List<YubinResponse0> res0 = ser.Deserialize<List<YubinResponse0>>(result);

                    foreach (YubinResponse0 r in res0)
                    {
                        addr += r.addr + "\r\n";
                    }
                }
                catch (Exception e)
                {
                    System.Diagnostics.Debug.Print(e.ToString());
                }
            }

            return addr;
        }

        public bool chkYubinNo(string yubinNo)
        {
            return (System.Text.RegularExpressions.Regex.IsMatch(
                yubinNo,
                @"^\d{3}-\d{4}$",
                System.Text.RegularExpressions.RegexOptions.ECMAScript));
        }

        string httpGet(string URI, string Parameters)
        {
            string result = "";

            try
            {
                System.Net.WebRequest req = System.Net.WebRequest.Create(URI);
                req.Method = "GET";

                System.Net.WebResponse resp = req.GetResponse();

                if (resp == null)
                {
                    return "";
                }

                System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream());
                result = sr.ReadToEnd().Trim();
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.Print(e.ToString());
            }

            
            return result;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("郵便番号を入力して Enter キーを押下してください。");
                Console.WriteLine("終了するには、なにも入力しないで Enter キーを押下してください。");

                Console.Write("郵便番号: ");
                string sin = Console.ReadLine();

                Yubin7 yubin7 = new Yubin7();

                while (sin != null && sin.Length > 0)
                {
                    if (yubin7.chkYubinNo(sin))
                    {
                        sin = sin.Replace("-", "");

                        string result = yubin7.getAddress(sin);

                        if (result.Length > 0)
                        {
                            Console.WriteLine(result);
                        }
                        else
                        {
                            Console.WriteLine("該当なし");
                        }
                    }
                    else
                    {
                        Console.WriteLine("郵便番号は7桁で 123-4567 の形式で入力してください。");
                    }

                    Console.Write("郵便番号: ");
                    sin = Console.ReadLine();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
    }
}
カテゴリー
C#

Fortran からC#への移行

Fortran で書かれたプログラムをC#へ移行なんてあまりないかもしれませんが、以前に経験したことをまとめてみました。

既存の FORTRAN アプリケーションがファイルや標準入出力から入出力(READ/WRITE)を行う部分がもっとも工数がかかると思われます。C# へ移行する際に入出力を見直すか、READ/WRITE ステートメントを補完する同等の機能を C# で実装する必要があります。

全体的なデザイン

  • C#で一つのクラスを作成しメインアプリケーションとする。Fortran プログラムのメイン部分を main 関数にて実装する
  • Fortran の各SUBROUTINEを クラスのPublic な関数として実装する。
  • Fortran のPARAMETER はクラス内のconst で変数で定義する
  • Fortran のCOMMON はクラス内の 変数で定義する
  • 算術 IF 文 「IF (式) 文番号, 文番号, 文番号」「GOTO (文番号, 文番号, …) 整数式」は if 文もしくは switch文にする
  • ENTRY はできる限り関数化する
  • Fortran アプリケーションの標準入出力へ出力している部分は、C#アプリケーションで別途関数を用意する。
  • (処理系によるが)浮動小数点型数値の扱いについて有効桁数がFORTRAN と C# で異なる場合、丸め誤差が発生する可能性があるので、C# 側で丸め処理を行い極力 FORTRAN と同程度の精度を確保する

Fortran データ型とC#のデータ型の対比

Fortran C#
REAL(4) float
REAL(8) double
REAL(16)
CHARACTER(1) byte
CHARACTER(*) string
INTEGER(1) sbyte
INTEGER(2) short
INTEGER(4) int
INTEGER(8) long

FORTRAN とC# のライブラリ関数

Fortran C#
ATAN2 Math.Atan2
NINT Math.Round 
*1 MidpointRounding.AwayFromZero
MIN0 Math.Min
MOD % 演算子
COS Math.Cos
CMPLX Complex クラス *2
AMIN1 Math.Min
AMAX1 Math.Max
ABS Math.Abs
SIGN — *3
SQRT Math.Sqrt
DCOS Math.Cos
DSIN Math.Sin
DSQRT Math.Sqrt
DATAN2 Math.Atan2
べき乗 Math.Pow
*1 : Roundメソッドで四捨五入
    MidpointRounding.AwayFromZero
*2 : Complexクラス
    .NET Framework 4.0 (Visual Studio 2010)より利用可能
*3 : シグモイド関数
    ex)  SIGN(x, y)

    y >= 0の場合 |x|
    y < 0の場合 -|x|

    float Sign(float x, float y)
    {
        if (y < 0)
            x = -x;
        return x;
    }

参考:
Fortran Reference: https://homepage2.nifty.com/nimu/docs/fortran_references.html
Equivalent Data Types between Fortran and C#: https://software.intel.com/en-us/articles/equivalent-data-types-between-fortran-and-c_sharp/
Using C/C++ and Fortran together: https://www.yolinux.com/TUTORIALS/LinuxTutorialMixingFortranAndC.html
Fortran ResQ: https://fortran.hiroshism.com/index.html

カテゴリー
C#

C# でファイル検索

C# でファイルを検索する簡単なプログラムを作成してみました。
Visual Studio 2010 で作成したので .NET Framework 4.0 で動作確認はしています。 MSDN のサンプルにあった、LINQ を使っていますので Visual Studio 2008/.NET Framework 3.5 以上です。

using System;
using System.Linq;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.IO;

namespace FindFiles
{
    class FindFiles
    {
        private int depthLevel = -1;

        public int DepthLevel
        {
            get { return depthLevel; }
            set { depthLevel = value; }
        }

        /// <summary>
        /// ファイル・フォルダの探索
        /// <param name="curFolder">ファイルを検索するフォルダ</param>
        /// <param name="curDepth">現探索レベル</param>
        /// </summary>
        void FindFilesRecurse(string curFolder, int curDepth)
        {
            // まず、現フォルダ内のファイルを検索
            try
            {
                IEnumerable<string> files = from file in 
                    Directory.EnumerateFiles(curFolder, "*")
// メモ: LINQ ここで WHERE 句で絞り込める
//                  where file.ToLower().StartsWith("something")
//  または、            where file.ToLower().Contains("something")
                    select file;

                foreach (string file in files)
                {
                    // 検索したファイルに対して何かする
                    Console.WriteLine(file);
                }
            }
            catch (Exception e)
            {
            }

            // 次に、探索のレベル指定により
            if (DepthLevel == -1 || DepthLevel > curDepth)
            {
                try
                {
                    // 現フォルダ内のサブフォルダを検索
                    IEnumerable<string> folders = from folder in 
                            Directory.EnumerateDirectories(curFolder, "*", SearchOption.TopDirectoryOnly)
                            select folder;

                    foreach (string f in folders)
                    {
                        // フォルダ再帰探索
                        FindFilesRecurse(f, curDepth + 1);
                    }
                }
                catch (Exception e)
                {
                }
            }
        }

        /// <summary>
        /// メイン
        /// </summary>
        static void Main(string[] args)
        {
            if (args.Length >= 2)
            {
                FindFiles ff = new FindFiles();

                // 検索開始フォルダ
                string folder = args[0];

                // 探索するフォルダの深さ
                int depth = int.Parse(args[1]);
                if (depth < 0)
                    depth = -1;
                ff.DepthLevel = depth;

                // 指定のフォルダが存在すれば探索開始
                string fullpath = System.IO.Path.GetFullPath(folder);

                if (System.IO.Directory.Exists(fullpath))
                {
                    ff.FindFilesRecurse(fullpath, 0);
                }
            }
            else
            {
                Console.WriteLine("使い方: FindFiles <"folder"> <level>");
                Console.WriteLine("        folder: 検索するフォルダ");
                Console.WriteLine("         level: 検索するフォルダの深さ");
                Console.WriteLine("    例: FindFiles c:Temp -1  --- すべてのサブフォルダを検索");
                Console.WriteLine("    例: FindFiles c:Temp 0   --- 指定のフォルダのみ検索");
                Console.WriteLine("    例: FindFiles c:Temp 3   --- 3階層までのフォルダ検索");
            }
        }        
    }
}