佐々木屋

技術的なことから趣味まで色々書きます

型変換は何を使う?(値型⇒String型)

今回は値型⇔string型です。共通認識は前回と一緒です。

  • VB.NETのCIntやCDecなどのC●●●は、CTypeと等価なので全てCTypeで検証
  • 時間計測はSystem.Diagnostics名前空間のStopwatchクラスを利用
  • 繰り返し回数maxは10,000,000回とする
  • それぞれを3回ずつ実行する

今回考えられる候補は、ToString、Convert、CType(VB.NETのみ)です。

int a = 123456789;

sw.Start();
for (int i = 1; i <= max; ++i) {
    string res = a.ToString();
}
sw.Stop();
Console.WriteLine(sw.Elapsed.ToString() + " ToString");
sw.Reset();

sw.Start();
for (int i = 1; i <= max; ++i) {
    string res = Convert.ToString(a);
}
sw.Stop();
Console.WriteLine(sw.Elapsed.ToString() + " Convert");
sw.Reset();
Dim a As Integer = 123456789

sw.Start()
For i As Integer = 1 To max
    Dim res As String = a.ToString()
Next
sw.Stop()
Console.WriteLine(sw.Elapsed.ToString() & " ToString")
sw.Reset()

sw.Start()
For i As Integer = 1 To max
    Dim res As String = Convert.ToString(a)
Next
sw.Stop()
Console.WriteLine(sw.Elapsed.ToString() & " Convert")
sw.Reset()

sw.Start()
For i As Integer = 1 To max
    Dim res As String = CType(a, String)
Next
sw.Stop()
Console.WriteLine(sw.Elapsed.ToString() & " CType")
sw.Reset()

結果は以下の通りです。

項目 C#
VB.NET
ToString 00:00:02.7788599
00:00:01.9934980
00:00:02.7895854
00:00:02.7907917
00:00:02.6248466
00:00:02.7211354
Convert 00:00:02.1907958
00:00:01.9914505
00:00:02.0879492
00:00:02.0197473
00:00:02.1154300
00:00:02.1438101
CType × 00:00:01.5729566
00:00:02.0180006
00:00:02.0006762


以外な結果です。最速はVB.NETのCType(CStr)でした。それでもToString、Convertと大差ありません。ToStringは書式指定が可能ですね。あとはnullの処理をどうするかだけかと思います。

結論、値型⇒String型はToStringで良いでしょう。

機械学習・・・(その①)

唐突ですが、機械学習を勉強してみようと思いました。


会社では一切使わない(将来的にも役に立たない)環境なのですが、前期出向で来ていたSさんが何とディープラーニングに手を出したとかなんとか。

どんなもんかと仕事の帰りに本屋に行って読んでみました。

どれどれ、なーんだ、線形代数の一般論ね~。
偏微分懐かしいなぁ・・・。
うん、色々忘れてるぞ~~(苦笑)。

前から気になっていたこともあり、手を出してみることに。こんなことなら大学卒業してからも少し勉強しておけばよかったと少し後悔・・・。でもその当時(20年前くらい)は「機械学習」なんて言葉無かったしね・・・(多分)。


取りあえず範囲的に高校数学程度かなぁと機械学習用の入門本を1冊買って読み進めてみましたが、高校数学だけではなく理系大学卒業程度の数学知識は必須のようです(流石に数学科までは不要ですが)。

わぁ、あの少しつらい記憶が蘇ります。頑張って単位とったっけなぁ。私はトポロジー位相幾何学)がとっても苦手な落ちこぼれ学生だったのです。


しかし、プログラミング歴2年のSさん、いきなりこれやっているって相も変わらず天才やな~、と感心しつつ、私は必要に駆られていない環境なので少し楽かも~、とか楽観視。


というわけで、週末とか空いた時間を利用して少しずつ思い出しの作業をしている今日この頃です。

ちゃっかり平行してPythonも勉強していたりして。早速本を1冊衝動買い。
books.rakuten.co.jp

管理者権限で自動実行されない・・・

Windows7と8(8.1)まではスタートアップから問題なく管理者権限で実行できていましたが、Windows10からは実行不可となっています。

UACを解除したり、アプリケーションマニフェストを変更したりしてみましたが効果ナシ・・・。ということで、別の方法を模索していましたが、サービスにするほどでもない(起動時一発で済むような)ので、最終的にタスクスケジューラにする方法で落着。

タスクスケジューラを作成します。
f:id:sasaki816:20191222221610j:plain:w600

作成画面の「トリガー」で、「ログオン時」を選択します。
f:id:sasaki816:20191222221615j:plain

あとはお好みで設定します。
マニフェストを変更しないのであれば、管理者権限で実行するにチェックするのをお忘れなく。


UACについてはこちら。
sasaki816.hatenablog.com


マニフェスト変更についてはこちら。
sasaki816.hatenablog.com

トリガーの登録

SQLServerのトリガ登録の覚えです。

INSERTやUPDATEなどでテーブルに変更があった場合に処理を呼ぶ場合に使用するのが「トリガ」です。
トリガーはテーブルごとの設定になります。

CREATE TRIGGER [ トリガー名 ] ON [ 対象テーブル名 ] 
AFTER { [ INSERT] , [ UPDATE ] , [ DELETE ] } 
AS BEGIN
[ 実行したいスクリプト ]
END



例えば、テーブル更新時に登録日時を自動で入れたい場合などは以下のようにします。

CREATE TRIGGER [dbo].[trig_取引明細TEST] ON  [dbo].[取引明細TEST] 
AFTER INSERT
AS BEGIN
UPDATE 取引明細EST SET 売上日 = getdate() WHERE 支店CD = (SELECT 支店CD FROM inserted)
END



insertedテーブルにはINSERT、UPDATEステートメント実行で影響を受けた行がコピーされます。そこのキーを指定すれば実テーブルを更新できる、というわけです。

従って、insertedテーブルにキーが無く、更新テーブルにもキーが無い場合は、実テーブルの意図しない行が更新されてしまう可能性がありますので注意が必要ということになります。


なお、設定はテーブルの「トリガー」に格納されます。
f:id:sasaki816:20191002131330j:plain

iPhoneのSafari対応 Javascriptからクリップボードを設定

会社の携帯が変更になるようで、それに伴い色々設定作業が入ります。
設定作業自体は部下にやらせるとして、やはり不用意にパスワードなどは見せたくないわけで。

そうした時にパスワードをクリップボード経由で扱えばいいのですが、iPhoneクリップボードはちょっと特殊のようで。


仕組みとして直接クリップボードへ値を入れることは出来ません。但し、テキストボックスの値を疑似的に選択状態にすればクリップボードへの代入が可能になります。

手順としては、ダミーのテキストボックス(txtPassword )を1個用意してそこに値を設定し、その値を選択状態にしてクリップボードへコピーします。

var txtPassword = document.getElementById("txtPassword ");
var range = document.createRange();
range.selectNode(txtPassword);
window.getSelection().addRange(range);
document.execCommand('copy');
alert("コピーしました。");

後は空文字をテキストボックスに代入し、それを同様の処理でクリップボードへコピーすればクリップボード内を削除出来ます。ダミーのテキストボックスの値は文字色を白にしたり、コピー直後にリダイレクトして値を削除したり、色々工夫すれば担当者レベルであれば目くらましになるでしょう。

MIMETypeの取得

ファイルのMIMETypeを取得する方法です。
.NET Frameworkによって違いますので、お好みの方をどうぞ。

.NET Framework4.5以上

System.Web.MimeMappingクラスのGetMimeMappingメソッドへファイル名を渡すことで取得可能です。

System.Web.MimeMapping.GetMimeMapping("ファイル名");
System.Web.MimeMapping.GetMimeMapping("ファイル名")

GetMimeMappingメソッドはフルパスを渡しても結果的には一緒です。恐らく内部的にファイル拡張子から判断しているものと思われます。

ですので、拡張子が認識できない場合はnullを返さずoctet-streamを返します。ファイル有無も関係ありません。

.NET Framework4.0まで

System.Web.MimeMappingクラスでは取得できませんので、ClassRootレジストリからContent Typeを取得する方法となります。

使い方によりけりですが、GetMimeMappingメソッドと合わせるならデフォルトでoctet-streamを返す仕様が好ましいです。あえてnullを返すという手もありますが、臨機応変にどうぞ。

private string GetMimeTypeByExtension(string ext) {
    string res = "application/octet-stream";

    try {
        var key = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
        if (key != null) {
            var mimetype = key.GetValue("Content Type");
            if (mimetype != null) res = (string)mimetype;
        }
    }
    catch { }

    return res;
}
Private Function GetMimeTypeByExtension(ByVal ext As String) As String
    Dim res As String = "application/octet-stream"

    Try
        Dim key = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext)
        If key IsNot Nothing Then
            Dim mimetype = key.GetValue("Content Type")
            If mimetype IsNot Nothing Then res = CType(mimetype, String)
        End If
    Catch ex As Exception
    End Try

    Return res
End Function



if文のところはnull条件演算子を使えばもっと簡潔に書けますが、.NET Framework4.0では使用できないので少し読みにくいですが仕方ありません。

IIS管理外の画像ファイルを表示させる

ASP.NETIIS管理内のディレクトリの画像ファイルをImageコントロールへ動的に表示させるためには以下で簡単にできますが、

img.ImageUrl = ”相対パス”

これを別のディレクトリに置いた画像を表示させたい場合は、System.Drawing名前空間のBitmapクラスへインスタンス展開して、それをResponse.OutputStreamに向けて保存すれば表示可能です。

protected void Page_Load(object sender, EventArgs e) {
    Bitmap bmp = new Bitmap(@"pngファイル絶対パス");
    Response.ContentType = "image/png";
    Response.Flush();
    bmp.Save(Response.OutputStream, ImageFormat.Png);
    Response.End();
}
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    Dim bmp As New Bitmap("pngファイル絶対パス")
    Response.ContentType = "image/png"
    Response.Flush()
    bmp.Save(Response.OutputStream, ImageFormat.Png)
    Response.End()
End Sub



で、ここまでは簡単な話ですが、ここで終わってはツマランわけで。
折角なので、MIMEや保存時のImageFormatを表示させるファイルの拡張子によって動的に設定できれば汎用性はぐっとあがります。

最初の1行目のビットマップクラスへの展開によって、ContentTypeとImageFormatを動的に取得するようなクラスを考えればよいことになります。

オブジェクト指向の観点を考慮しつつ構築する演習としてみましょう。
ということで、このまま演習へ引き継ぎます。