Help us understand the problem. What is going on with this article?

【C#】C#から%d(変換指定子)を呼び出す【F#】

More than 3 years have passed since last update.

【C#】C#から%d(変換指定子)を呼び出す【F#】

C#ではCやC++、Pythonなどで利用されている変換指定子が直接利用できないため、
C#上からF#のライブラリを呼び出し、変換指定子付きの書式フォーマットを利用します。

C++で作成されているシステムのC#への移行を行う場合等、何かしら今後利用することがありそうな気がするので、
私的メモとしてここに残しておきます。

環境

VisualStudio 2015
FSharp.Core 4.4.0.0

経緯

変換指定子(書式化文字列)って?

変換指定子とは、

%[flags][width][.precision][modifier]type

のような形を用いて、出力するデータの書式を指定します。
例としては%dや、%.3fのような形で用いられ、それぞれ「10進数での表示」、
「小数点以下3桁までの表示」となります。変換指定子の詳しい記法等は下記参照。
http://www.tamasoft.co.jp/lc/hlp/F056.html

それってC#でもできんじゃね?

C#のToString()を用いて、書式指定の文字列変換を行うことはできますが、
これはCやC++で利用される変換指定子利用とは全く違う形です。ですので、今までC++で作成してきたシステムの
何かを利用する場合、同じように利用できない場合が多いでしょう。

じゃあC++でやればいいじゃん。

確かに、C++のライブラリを作成してC#から呼び出すこともできますが、
stringの扱いや、型の扱い(floatの場合、intの場合、decimalの場合、stringの場合・・・)等、
ライブラリを呼び出す制御作成自体が少し大変であり、時間が掛かってしまいます。

勿論、元がC++のコードで、それを移行するだけであればその方法の方が良いかとは思いますが、
現実的にはそうできない場合も多いため、今回はF#での実装を行いました。

ソースコード

F#部分

namespace SprintFTest.Formatter

module Format = begin
    /// 変換指定子を用いて文字列を変換する
    let SprintF style value : string =
        // 受け取った書式文字列をPrintFormat型にキャスト
        let f = Printf.StringFormat<_>(style)
        // sprintfで書式変更した結果を返却
        sprintf f value
end

変換指定子を利用するために、F#のsprintfメソッドを利用します。
引数の型指定はせず、返り値のみの指定とし、あくまでF#のsprintfを呼び出すだけのメソッドとしています。

これをC#側から呼び出せばokです。参照に追加するのを忘れないように!

C#部分

using System;

namespace SprintFTest
{
    class Program
    {
        /// <summary>
        /// メインエントリ
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            //変換指定子
            string format = "%.2f\n";       //小数点以下2桁までとし、行末改行
            string format2 = "%.5finch";    //小数点以下5桁までとし、inchを付加
            string format3 = "%x";          //符号なし16進数として出力する

            //変換指定子を使って数値を変換したい!
            Console.WriteLine(Format(format, 3.1415926535));
            Console.WriteLine(Format(format2, 3.1415926535));
            Console.WriteLine(Format(format3, 269));

            //結果表示
            Console.ReadLine();
        }

        /// <summary>
        /// F#を呼び出して書式変換を行う
        /// </summary>
        private static string Format<T>(string style,T value)
        {
            return Formatter.Format.SprintF(style, value);
        }
    }
}

Format(string style,T value)というラッパーを用意し、F#のSprintFメソッドを呼び出します。
F#側では動的型付けを用いて変換を行っているので、第二引数にはジェネリック Tを用いています。
これにより、変換対象となるデータがintであっても、floatであっても、意識することなく変換を行うことが出来ます。

※変換対象データと書式が合わない場合(変換指定子が.3fなのにデータがintの場合)などは適切な制御が
必要と考えられます。その場合は、Mainから呼び出されFormatを呼び出す仲介メソッドを作成し、
そこでキャスト処理等を加えてやるとよいでしょう。

出力結果

1.PNG

プロジェクトの全体構成

C.PNG

感想

ニッチなメモになってしまいましたが、そのうち使う機会が訪れる・・・かも・・・?
とりあえず、表示に%d使えないからC#やめてC++で開発しよう!とかそういう判断はしたくないので、
忘れないようにします。

参考リンク

http://www.tamasoft.co.jp/lc/hlp/F056.html

logikuma
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away