カテゴリー
C#

“YYYYMMDDHHMMSS”形式の日付を DateTime へ変換(C#)

“YYYYMMDDHHMMSS” 形式の日付を DateTime へ変換というのは、あまりにも当たり前すぎるのか例が少ない気がします。4桁、2桁… で文字列を切り出し DateTime へ変換するのも良いですが、DateTime.ParseExact でやる方法があります。

string str = "20130118105501";
DateTime dt;

// このまま Convert.ToDateTime を呼ぶと例外になる。
//  dt = Convert.ToDateTime(str);

// ParseExact で "yyyyMMddHHmmss" 形式の日付として解析
dt = DateTime.ParseExact(str, "yyyyMMddHHmmss",
                         System.Globalization.CultureInfo.InvariantCulture);
Console.WriteLine(str + "==> OK." + dt.ToString());

出力結果:

20130118105501==> OK.2013/01/18 10:55:01
カテゴリー
C#

C# で HTTP GET を行う場合の例外処理

C# でHTTPを使ってサーバーからコンテンツを取得する際に起こり得る例外処理を調べて、catch で処理できるようコードを書いてみました。

HTTP ステータスコードの 401(未認証), 403(アクセス拒否) やネットワークケーブルを抜いた場合などは WebException でキャッチできるようです。

参考:
https://msdn.microsoft.com/ja-jp/library/system.net.webrequest(v=vs.80).aspx
https://msdn.microsoft.com/ja-jp/library/system.net.httpwebrequest.getresponse(v=vs.80).aspx
https://www.java2s.com/Code/CSharp/Network/Handlenetworkexceptions.htm
https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

using System;
using System.Net;
using System.IO;

namespace webget
{
    class WebGet
    {
        static void Main(string[] args)
        {
            if (args.Length < 1)
            {
                Console.WriteLine("URL を指定してください。");
                return;
            }

            WebGet w = new WebGet();

            string s = w.HttpGet(args[0], "");
        }

        public string HttpGet(string URI, string Parameters)
        {
            string res = "";
            Stream dataStream = null;
            StreamReader reader = null;
            HttpWebResponse response = null;

            try
            {
                // URLの HTTP リクエストを作成. 		
                WebRequest request = WebRequest.Create(URI);

                // デフォルトのクレデンシャルを設定.
                request.Credentials = CredentialCache.DefaultCredentials;
                
                // HTTP レスポンスを取得.
                response = (HttpWebResponse)request.GetResponse();

                // ステータスの表示.
                Console.WriteLine(response.StatusDescription);
                
                // サーバーからコンテンツを含むストリームを取得.
                dataStream = response.GetResponseStream();
                
                // ストリームを開く
                reader = new StreamReader(dataStream);

                // コンテンツの読み込み.
                string responseFromServer = reader.ReadToEnd();

                // コンテンツの表示.
                Console.WriteLine(responseFromServer);
            }
            catch (WebException e)
            {
                // ネットワークが切断されているような場合 etc...
                Console.WriteLine("Web 例外 - " + e.Status + " : " + e.Message);
            }
            catch (UriFormatException e)
            {
                // https:///www.northwind.mydns.jp/samples のような場合
                //      ^^^
                Console.WriteLine("URI フォーマット不正: " + e.Message);
            }
            catch (System.Security.Authentication.AuthenticationException e)
            {
                Console.WriteLine("セキュリティ認証エラー: " + e.Message);
            }
            catch (InvalidOperationException e)
            {
                Console.WriteLine("無効な操作: " + e.Message);
            }
            catch (NotSupportedException e)
            {
                // htt:///www.northwind.mydns.jp/samples のような場合
                // ^^^
                Console.WriteLine("未サポートのプロトコル: " + e.Message);
            }
            catch (Exception e)
            {
                Console.WriteLine("予期しないエラー: " + e.ToString());
            }
            finally
            {
                // Cleanup the streams and the response.
                if (reader != null)
                    reader.Close();
                if (dataStream != null)
                    dataStream.Close();
                if (response != null)
                    response.Close();
            }
            
            return res;
        }
    }
}
カテゴリー
C#

C# データテーブルの内容をCSV出力

C#/ASP.NET でデータテーブルの内容を CSV 出力するサンプルを作成しました。
VisualStudio 2008 で動作確認しています。

using System;
using System.Data;
using System.IO;

namespace WebApplication1
{
    public class DT : System.Data.DataTable
    {
        private string lastError = string.Empty;

        public string LastError
        {
            get { return lastError; }
            set { lastError = value; }
        }

        ///
        /// CSV形式で出力
        ///
        public bool SaveToStream(MemoryStream ms, string rowDelim,
                                 char colDelim, char celDelim, int codepage)
        {
            bool result = true;

            try
            {
                // ヘッダ部
                string line = string.Empty;

                foreach (DataColumn col in this.Columns)
                {
                    line += celDelim;

                    line += col.Caption;

                    line += celDelim;

                    line += colDelim;
                }
                // 末尾の ',' 取り除く
                line = line.TrimEnd(colDelim);
                // 改行の付加
                line += rowDelim;

                // ストリームへ出力
                byte[] byteArray = System.Text.Encoding.GetEncoding(codepage).GetBytes(line);
                ms.Write(byteArray, 0, byteArray.Length);

                // データ部
                int colCount = this.Columns.Count;

                foreach (DataRow row in this.Rows)
                {
                    line = string.Empty;

                    for (int i = 0; i < colCount; i++)
                    {
                        // フィールドの取得
                        string field = row[i].ToString();

                        line += celDelim;

                        line += field;

                        line += celDelim;

                        line += colDelim;
                    }
                    // 末尾の ',' 取り除く
                    line = line.TrimEnd(colDelim);
                    // 改行の付加
                    line += rowDelim;

                    // ストリームへ出力
                    byteArray = System.Text.Encoding.GetEncoding(codepage).GetBytes(line);
                    ms.Write(byteArray, 0, byteArray.Length);
                }
            }
            catch (Exception e)
            {
                LastError = e.ToString();
                result = false;
            }

            return result;
        }
        ///
        /// サンプル データ作成
        ///
        public void MakeSampleTable()
        {
            DataColumn column;
            DataRow row;

            // DataColumn の作成
            // 1列目を作成
            column = new DataColumn();
            column.DataType = System.Type.GetType("System.Int32");
            column.ColumnName = "ID";
            column.ReadOnly = true;
            column.Unique = true;
            this.Columns.Add(column);

            // 2列目を作成.
            column = new DataColumn();
            column.DataType = System.Type.GetType("System.String");
            column.ColumnName = "データ";
            column.AutoIncrement = false;
            column.Caption = "データ";
            column.ReadOnly = false;
            column.Unique = false;
            this.Columns.Add(column);

            // ID列を主キーに設定
            DataColumn[] PrimaryKeyColumns = new DataColumn[1];
            PrimaryKeyColumns[0] = this.Columns["ID"];
            this.PrimaryKey = PrimaryKeyColumns;

            // データセットを作成してデータを作成
            DataSet dataSet = new DataSet();
            dataSet.Tables.Add(this);
            // データを10件追加
            for (int i = 0; i <= 10; i++)
            {
                row = this.NewRow();
                row["ID"] = i;
                row["データ"] = "データ " + i;
                this.Rows.Add(row);
            }
        }
    }

    public partial class _Default : System.Web.UI.Page
    {
        const string rowDelim = "rn";
        const char colDelim = ',';
        const char celDelim = '"';
        const int codepage = 932;
        const string csvname = "sample.csv";

        protected void Page_Load(object sender, EventArgs e)
        {

        }

        ///
        /// クライアントへCSV出力
        ///
        protected void Button1_Click(object sender, EventArgs e)
        {
            DT dt = new DT();
            dt.MakeSampleTable();

            // サンプル データを MemoryStream にへ出力
            System.IO.MemoryStream ms = new System.IO.MemoryStream();

            if (!dt.SaveToStream(ms, rowDelim, colDelim, celDelim, codepage))
            {
                System.Diagnostics.Debug.Print(dt.LastError);
            }

            // MemoryStream をクライアント側へ送信
             Response.Clear();
            Response.ContentType = "application/octet-stream";
            Response.AddHeader("Content-Disposition", "attachment;filename=" + Server.UrlEncode(csvname));
            Response.BinaryWrite(ms.ToArray());

            ms.Close();
            Response.Close();
        }
    }
}
カテゴリー
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