ラベル プログラミング の投稿を表示しています。 すべての投稿を表示
ラベル プログラミング の投稿を表示しています。 すべての投稿を表示

TikaOnDotnetでファイル内の文字列を抽出する方法

 以下のSampleのとおり、TextExtractor.Extract()メソッドで、ファイル内の文字列を取得できます。

※Shift-Jisのテキストファイル(.txt)は、UTF-8に変換しないと抽出に失敗するので要注意。

public void TikaExtractorTest() {
    var txtExtractor = new TextExtractor();

    var path = @"C:\Temp\Test.xlsx";
    var content = txtExtractor.Extract(path);

    Debug.WriteLine(content.Text);
}

C#で文字コードを自動判定する方法

 以下のSampleのとおり、ReadJEnc.JP.GetEncoding()メソッドで文字コードを自動判定することができます。

実装例

public void DetectingEncodeTest() {
    var path = @"C:\Temp\Test.txt";

    byte[] bytes = null;
    using (var fs = new FileStream(path, FileMode.Open)) {
        bytes = new byte[fs.Length];
        fs.Read(bytes, 0, bytes.Length);
    }
    string str = null;
    var encode = ReadJEnc.JP.GetEncoding(bytes, bytes.Length, out str);

    Debug.WriteLine(encode.ToString());
}

実行結果

ShiftJIS

FlexLuceneで日付フィルタリングを実現する方法

 ポイントは、以下の2点です。

  • ドキュメントの日付を、同一フィールド名でLongPointとStoredFieldを使って登録する。(17行目付近)
  • 検索時にLongPoint.NewRangeQueryを使って、絞込みを行う点です。(32行目)

実装例

public void LongPointTest() {
    var analyzer = new WhitespaceAnalyzer();
    var iwc = new IndexWriterConfig(analyzer);

    iwc.SetOpenMode(IndexWriterConfigOpenMode.CREATE);

    //テスト用インデックス作成---------------------------------------------
    DateTime baseDate = DateTime.Parse("2020/07/16 08:00:00");
    var ram = new RAMDirectory();
    var writer = new IndexWriter(ram, iwc);
    try {
        for (int i = 0; i < 10; i++) {
            var doc = new Document();
            doc.Add(new TextField("text", "hoge foo", FieldStore.YES));
            DateTime tmp = baseDate.AddDays(i);
            long l = long.Parse(tmp.ToString("yyyyMMddHHmmss"));
            //日付文字列をlong値で保持
            doc.Add(new LongPoint("date", l));
            //long値をストアするには、同じフィールド名でStoredFieldとして指定する必要がある。
            doc.Add(new StoredField("date", l));

            writer.AddDocument(doc);
        }
        
    } finally {
        writer.Close();
    }

    //検索------------------------------------------------------------
    TermQuery tq = new TermQuery(new Term("text", "foo"));
    //日付範囲の条件
    Query rq = LongPoint.NewRangeQuery("date", 20200717000000, 20200719000000);

    BooleanQueryBuilder b = new BooleanQueryBuilder();
    b.Add(tq, BooleanClauseOccur.MUST); //AND条件
    b.Add(rq, BooleanClauseOccur.FILTER); //AND条件(スコアリングに関与しない)
    Query q = b.Build();

    DirectoryReader dr = DirectoryReader.Open(ram);
    IndexSearcher searcher = new IndexSearcher(dr);
    ScoreDoc[] hits = searcher.Search(q, 100).ScoreDocs;
    for (int i = 0; i < hits.Length; i++) {
        var doc = searcher.Doc(hits[i].Doc);
        Debug.WriteLine(DateTime.ParseExact(doc.Get("date"), "yyyyMMddHHmmss", null));
    }
}

検索結果

2020/07/17 8:00:00
2020/07/18 8:00:00

Outlookで送信前に宛先確認ダイアログを表示する方法

 

Outlookで送信前に宛先確認ダイアログを表示する方法

  • Alt + F11を押して、VBAエディタを表示。
  • 以下のスクリプトをThisOutlookSessionに記述してください。
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
    '件名未記入の確認
    If Item.Subject = "" Then
        If MsgBox("このメッセージには件名がありません。" & vbCrLf & _
            "[OK] をクリックすると送信します。", vbOKCancel + vbExclamation + vbMsgBoxSetForeground) = vbCancel Then
            Cancel = True
            Item.GetInspector.Activate
            Exit Sub
        End If
    End If
    '送信確認ダイアログ
    If MsgBox("宛先、添付ファイル、文面を再度確認してください。" & vbCrLf & _
        "送信しますか?", vbOKCancel + vbQuestion + vbMsgBoxSetForeground) = vbCancel Then
        Cancel = True
        Item.GetInspector.Activate
        Exit Sub
    End If
End Sub

【プレミア本】Human Interface Guidelines:The Apple Desktop Interface(日本語版)

 

どんな本?


今日のパーソナルコンピュータのGUI(グラフィカルユーザインタフェース)の手本となった、 アップル社のマン・マシンインタフェース設計基準を解説した本です。 GUIの設計思想を含め、多くのデザイナーにとって重要な本として今でも様々な書物で、参照されている名著です。 現在は絶版となっており、またその内容は20年を経た今も色あせておらず。プレミア価格が付いております。

出版社出版日
新紀元社2004/07

Amazonでの価格



メルカリでの取引実績


ポイント

ヒューマンインタフェースデザイン原則

  • 隠喩

    • アプリケーションの機能と概念を伝えるために、現実世界に例えて表現すること。
      • 「ファイル」と「フォルダ」の関係
      • 押せることを表す「ボタン」
      • 「ゴミ箱」
  • ユーザの心のモデルを反映せよ

    • 親しみやすさ
    • 単純さ
    • 利用しやすさ
    • 発見可能性
  • 明示的な動作と暗黙の動作

    • 明示的な動作
      • 実行したいコマンドのメニューを選択する。
    • 暗黙の動作
      • ファイルをゴミ箱にドラッグドロップする。(ファイルを削除)
  • 直接的な操作

    • ドラッグ、ドロップ操作
  • ユーザによる制御

  • 反応と伝達

    • 時間のかかる操作を伝える。
  • 一貫性

  • WYSIWYG

    • 見た目通り印刷できる。
  • 寛容性

    • アンドゥ、リドゥ
  • 認識の安定感

    • チェックボックス、ボタンなどユーザがすぐに認識できるUI
  • 美観の完成

    • アイコン
    • フォントの大きさ、TrueTypeフォント
  • モードの排除

    • 出来る限りユーザの望む操作をいつでも行えるようにする。
  • あなたのソフトフェアでの複雑さを管理する

    • 出来る限りデザインを単純に保つ

最新OSのガイドラインはWeb(英語)でも確認できます。

C#でGoogle Maps APIを使う(2点間の距離を取得)

Google Maps APIを使って2点間の距離を取得するメソッドを実装してみました。

public static double GetDistance(string origin, string destination, string apiKey) {
    double ret = 0;
    WebResponse response = null;
    try {
        string url = @"https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + 
            origin + "&destinations=" + destination + "&key=" + apiKey;

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        response = request.GetResponse();
        Stream dataStream = response.GetResponseStream();
        StreamReader sReader = new StreamReader(dataStream);
        string jsonString = sReader.ReadToEnd();
        Debug.Write(jsonString);

        var jo = JObject.Parse(jsonString);
        JToken jt = jo.SelectToken("$.rows..elements..distance.value");
        ret = double.Parse(StringUtil.NullBlankToZero(jt.ToString()));

        return ret;
    } finally {
        response.Close();
    }
}

例えば「origin:東京」-「destination:大阪」を指定してリクエストを投げると、以下の形式のJSONが返されるので、
JSONPathを使って、距離の部分を抜き出して戻り値にセットしています。

●例)「東京」-「大阪」間でリクエストを投げた時のJSON取得結果
{
   "destination_addresses" : [ "Osaka, Osaka Prefecture, Japan" ],
   "origin_addresses" : [ "Tokyo, Japan" ],
   "rows" : [
      {
         "elements" : [
            {
               "distance" : {
                  "text" : "513 km",
                  "value" : 512545
               },
               "duration" : {
                  "text" : "6 hours 16 mins",
                  "value" : 22563
               },
               "status" : "OK"
            }
         ]
      }
   ],
   "status" : "OK"
}

Simple Injectorを使ってみた


手軽に利用できるDIコンテナ「Simple Injector」を使ってみました。
パッケージ開発のアドオンの受け口などで活用できそうです。

●このデモで利用するクラス一覧
クラス/インタフェース 説明
Program.cs このクラスで以下の処理を行います。
・コンテナ生成
・注入オプジェクト登録
・コンテナの登録内容の検証
・InjectionTargetClassのメソッドを実行
IProxy.cs 注入オブジェクトのインタフェースです。
HogeProxy.cs 注入オブジェクトの具象クラス。
FooProxy.cs 注入オブジェクトの具象クラス。
BarClass.cs 注入オブジェクトの具象クラス。(IProxyは実装していない。)
InjectionTargetClass.cs オブジェクト注入対象のクラスです。
このクラスで注入されたオブジェクトを利用します。
コンストラクタの引数に注目してください。
コンテナに登録されたオブジェクトが渡されます。

●Program.cs
using SimpleInjector;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleInjectorInConsoleApp {
    class Program {

        private static Container container;

        static void Main(string[] args) {
            
            container = new Container();

            //デフォルトのLifestyleを確認
            Console.WriteLine("デフォルトのLifestyle : " + container.Options.DefaultLifestyle.ToString());

            container.Register(Lifestyle.Singleton);
            //登録をFooProxyに切替えると、利用側のクラスを変更せずに処理を切り替えれます。
            //container.Register(Lifestyle.Singleton);

            //コンストラクタにRegister()していないTypeの引数を渡す方法
            container.Register(() => new BarClass("bar"), Lifestyle.Singleton);

            container.Verify();

            // Useコンテナに登録していないが、コンストラクタインジェクションを行って必要な
            // オブジェクトを設定してインスタンスを作成してくれる。 (auto-wiring)
            var a = container.GetInstance();
            a.Write();

            //自動でコンソールが閉じるの防ぐ
            Console.ReadLine();
        }
    }
}

●IProxy.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleInjectorInConsoleApp {
    /// 
    /// インタフェース
    /// 
    public interface IProxy {
        void Write();
    }
}

●HogeProxy.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleInjectorInConsoleApp {
    /// 
    /// 注入クラスHoge
    /// 
    class HogeProxy : IProxy {
        public void Write() {
            Console.WriteLine("hoge");
        }
    }
}

●FooProxy.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleInjectorInConsoleApp {
    /// 
    /// 注入クラスFoo
    /// 
    class FooProxy : IProxy {
        public void Write() {
            Console.WriteLine("foo");
        }
    }
}

●BarClass.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleInjectorInConsoleApp {
    /// 
    /// 注入クラスBar
    /// ※ IProxyを実装していない
    /// 
    public class BarClass {
        private string val = "";
        public BarClass(string str) {
            val = str; 
        }

        public void Write() {
            Console.Write(val);
        }
    }
}

●InjectionTargetClass.cs
using SimpleInjector;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleInjectorInConsoleApp {
    /// 
    /// オブジェクト注入対象クラス
    /// 
    public class InjectionTargetClass {
        private readonly IProxy _proxy;
        private readonly Container _container;
        private readonly BarClass _dummy;

        public InjectionTargetClass(IProxy proxy, Container container, BarClass dummy) {
            _proxy = proxy;
            _container = container;
            _dummy = dummy;
        }

        public void Write() {
            _proxy.Write();
            Console.WriteLine("注入コンテナのDefaultLifestyle : " + 
                _container.Options.DefaultLifestyle);
            _dummy.Write();
        }
    }
}

●実行結果

Sencha ExtJs ModernでLoadMaskを実装

LoadMaskの実装方法をメモ。
Ext.deferを使って、非同期処理完了後にmask.hide()を呼び出すのがポイント。

以下のサンプルは、「Run」ボタンタップ後、5秒間LoadMaskを表示し、後続処理を実行します。
デモ&ソース

Sencha ExtJsでポーリング処理

ポーリング処理を実装するには、Ext.util.TaskRunnerを使います。
Classic Toolkit、Modern Toolkit共通で利用できます。

以下のサンプルは、ブラウザのコンソールに1秒間隔でログを記述します。
デモ&ソース

Microsoft Teamsにエラーログを出力するLog4Net Custom Appenderを作ってみた。


Custom AppenderクラスはAppenderSkeletonを継承し、Append()メソッドをオーバライドして作成。
IncomingWebhooksのURLをlog4net.configから取得できるようにプロパティを作成しておく。

●Custom Appenderクラスは以下のとおり。
 MSTeamsUtil()の実装についてはこちらを参考にして下さい。
public class MSTeamsAppender : AppenderSkeleton {

    //Microsoft TeamsのコネクタURL
    public string IncomingWebhookURL { getset; }  

    // Microsoft Teamsにログ追記
    protected override void Append(LoggingEvent loggingEvent) {
        var mstu = new MSTeamsUtil();
        mstu.PostPlainMessage(IncomingWebhookURL, RenderLoggingEvent(loggingEvent));
    }
}
●log4net.configの設定方法は以下のとおり
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <log4net>
    <appender name="MSTeamsAppender" type="FxCommonLib.Log4NetAppender.MSTeamsAppender, FxCommonLib">
      <incomingWebhookURL value="https://outlook.office.com/・・・" />
      <layout type="log4net.Layout.PatternLayout">
        <ConversionPattern value="%username %d [%t] %-5p %c - %m%n" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="WARN" />
        <levelMax value="FATAL" />
      </filter>
    </appender>
    <root>
      <level value="INFO" />
      <appender-ref ref="MSTeamsAppender" />
    </root>
  </log4net>
</configuration>
こんな感じでログが投稿されます。

Microsoft TeamsにC#でメッセージ投稿してみた


最近、無償提供されたMicrosoft Teamsにプログラムからメッセージ投稿してみたいと思い、実装してみた。
システム監視、センサなどから情報投稿など、いろいろ利用できそう。

まずは、Microsoft TeamsのIncoming Webhook APIのURLを取得。
取得方法の詳細はこちら

○Microsoft Teamsに平文メッセージを投稿するためのユーティリティメソッド
public class MSTeamsUtil {
    // Microsoft Temasに平文メッセージを投稿
    public void PostPlainMessage(string webhookURL, string message) {
        using (var client = new WebClient()) {
            var param = new Dictionary();
            // Textパラメータは必須
            param["Text"] = message;
            var json = JsonConvert.SerializeObject(param);

            client.Headers.Add(HttpRequestHeader.ContentType, "application/json;charset=UTF-8");
            client.Encoding = Encoding.UTF8;
            client.UploadString(webhookURL, json);
        }
    }
}
○利用側のソース
public class MSTeamsUtilTest {
    //取得したImcoming WebhooksのURLをセット
    private string _webhookURL = "https://outlook.office.com/webhook/・・・";

    public void PostPlainMessageTest() {
        var mst = new MSTeamsUtil();
        mst.PostPlainMessage(_webhookURL, "hoge hoge");
    }
}
最初、HttpClientで実装しようとしたが、PostAsAsync()実行時にエラー(ExceptionもCatchできない状態)となった。
エラーの原因は、よく解らないので、追々調査してみることに。

代わりにWebClientに変更して実装してみるとメッセージ投稿に成功した。

なお、HttpClientを利用する時はリクエストの度にインスタンス生成・破棄してはならにとのこと。
TCPコネクションが都度、張られ、パフォーマンスを低下させるとのこと。

WebClientではリクエストの度にインスタンス生成・破棄してもTCPコネクションが使い回されるため問題ない。

【参考】
C# HTTPクライアントまとめ
不適切なインスタンス化のアンチパターン

厳選 Visual Studioの便利なショートカット

  エラー箇所にジャンプ 「Ctrl + Shift + F12」 ブレークポイント 設定/解除 「F9」 有効化/無効化 「Ctrl + F9」 ViEmu特有 「:ls」:バッファナンバーのリストを表示。 「:b2」:バッファ2のファイルを開く。 「:n」:次のバッファのファ...