今日、私はハブに目を向け、ベース自体の説明に特化したトピック - トピックを見つけました。また、このまさにベース- トピックとSkypeLogViewerの言及を復元しました。 素晴らしい、私は別の硬い自転車を書く時が来たと思った。
アイデアは簡単です:luaを使用してチャットを選択およびフィルタリングするのは、lua、sqlクエリ、およびlinqのluaアナログを少し練習したい人や、標準のSkype検索に慣れていない人向けです。 アプリケーション自体はC#(WPF)で記述されています。
何が起こった-カットの下を見てください。
それでは、簡単なものから始めましょう-luaとsqliteで動作するために必要なライブラリを接続します。
選択はそれぞれNLuaとSystem.Data.Sqliteに当てはまりました。 インストールにはNuGetを使用します。
インストールパッケージnlua
インストールパッケージsystem.data.sqlite
便宜上、すべての消防士のために、luaの小さなラッパークラスを作成します
public class LuaLogic { public Lua lua = new Lua(); // public - C# lua public void reg(object target, string funcname) { try { lua.RegisterFunction(funcname, target, target.GetType().GetMethod(funcname)); } catch (Exception ex) { } } // lua- public object[] call(string lua_func, params object[] args) { try { var func = lua[lua_func] as LuaFunction; return func.Call(args); } catch (Exception ex) { return null; } } }
そして、はい、多くの人が例外をスローすべきだと考えていることを知っています-この特定のケースではこれの必要性が見えないだけです。
ここではコードで使用されるGUI要素の説明があるため、GUIのマークアップを投稿しません。
出力-下品なジョークやアスキーアートなど、あらゆる種類の情報を出力するためのRichTextBox
runlua-ボタン。luaコードを実行します。 実際には、 FileSystemWatcherを使用してファイルを変更することで一時停止できますが、これはすべてのユーザー向けではありません
アカウント-ComboBox。コンピューターにログオンしたことのあるSkypeユーザーを一覧表示します。
それでは、コードに移りましょう。 ヘルパー関数から始めましょう。
static LuaLogic logic = new LuaLogic(); public string current_path = ""; private List<Dictionary<string, object>> data; // . - . private List<Dictionary<string, object>> _query(string comm) { var result = new List<Dictionary<string, object>>(); using (var db = new SQLiteConnection(@"data source=" + current_path)) { db.Open(); using (var command = new SQLiteCommand(comm, db)) { command.CommandTimeout = 999; using (var reader = command.ExecuteReader()) { while (reader.Read()) { result.Add(Enumerable.Range(0, reader.FieldCount) .ToDictionary( reader.GetName, reader.GetValue)); } } } db.Close(); } return result; } // lua . , List<Dictionary<string, object>> lua . lua-, lua-. public LuaTable genTable(List<Dictionary<string, object>> d) { logic.lua.NewTable("datatable"); var table = logic.lua.GetTable("datatable"); for(int i=0; i<d.Count; i++) { logic.lua.NewTable("f"); table[i] = logic.lua.GetTable("f"); foreach (var entry in d[i]) { ((LuaTable) table[i])[entry.Key] = entry.Value; } } return table; } /*** , lua ***/ //, . lua . public void scanDB(string request=null) { if(data!=null) data.Clear(); data = new List<Dictionary<string, object>>(); data = _query(request??"select from_dispname,body_xml,timestamp from messages order by timestamp desc"); genTable(data); } // RichTextBox public void _print(object obj) { Dispatcher.Invoke(() =>output.AppendText(obj + "\n")); } // 1 RichTextBox. . public void _printblock(string text) { Dispatcher.Invoke(() => output.Document.Blocks.Add(new Paragraph(new Run(text)) { Margin = new Thickness(0) })); } // RichTextBox public void _clear() { Dispatcher.Invoke(() => output.Document.Blocks.Clear()); }
そして今-アプリケーションロジック!
public MainWindow() { InitializeComponent(); // . - , var searchpath = Environment.ExpandEnvironmentVariables("%AppData%\\Skype"); var dirs = Directory.GetDirectories(searchpath); // , var userlist = dirs.Where(dir => File.Exists(dir + "\\main.db")).Select(x=>x.Replace(searchpath+"\\", "")).ToList(); accounts.ItemsSource = userlist; accounts.SelectedItem = accounts.Items[0]; // ComboBox' accounts.SelectionChanged += (sender, args) => current_path = Environment.ExpandEnvironmentVariables("%AppData%\\Skype") + "\\" + accounts.SelectedItem + "\\main.db"; if(userlist.Count>0) current_path = Environment.ExpandEnvironmentVariables("%AppData%\\Skype") + "\\" + userlist[0] + "\\main.db"; else { _print(" , ?"); } // Lua logic.reg(this, "_print"); logic.reg(this, "_clear"); logic.reg(this, "_printblock"); logic.reg(this, "scanDB"); runlua.Click += (sender, args) => { try { new Thread(() => { // 2 - linq- where select , , . Lua-linq <a href="http://codea.io/talk/discussion/618/linq-for-lua-functional-collection-class/p1"></a>. logic.lua.DoFile(@"scripts\pseudolinq.lua"); logic.lua.DoFile(@"scripts\script.lua"); // , lua-. , , lua- logic.call("search_pattern"); }).Start(); } catch (Exception ex) { _printblock(ex.Message); } }; // , , Closing += (sender, args) => Process.GetCurrentProcess().Kill(); }
まあ、軽食のために-ルアコード。
pseudolinq.lua
LinqArray = {} function LinqArray:new( arr ) Ret = {} Ret.arr = arr; setmetatable( Ret , self ) self.__index = self; return Ret; end --[[function LinqArray:init(items) if items then self:addRange(items) end end]]-- function LinqArray:add(item) table.insert(self.arr, item) end function LinqArray:addRange(items) for k,v in ipairs(items) do self.arr:add(v) end end function LinqArray:where(func) local results = {}; for k, v in ipairs(self.arr) do if func(v) then table.insert(results, v); end end return LinqArray:new(results) end function LinqArray:select(func) local results = {} for k, v in ipairs(self.arr) do _print(func(v)); table.insert(results, func(v)); end return LinqArray:new(results) end
script.lua
function search_pattern() -- _clear(); local f = LinqArray:new(datatable); -- - linq- local filtered = f:where(function(x) return string.len(x["from_dispname"])>1; end):select(function(x) return x["from_dispname"]; end); -- . . , , . - . local i=0; for i=1,#filtered.arr,1 do local arg = filtered.arr[i]; _printblock(arg["from_dispname"]..": "); _print(arg["body_xml"]); end end --, . . , 1 , lua, if(datatable==nil) then scanDB("select * from messages limit 100"); end
フィルターについて詳しく説明します。
一般に、linqのような形式で行う必要はなく、フィルター自体はリクエストで作成できますが、これは「異常なプログラミング」ハブであるため、明らかでない何かを追加する必要があります。
停止が完了しました。
原則として、それだけです。
ご清聴ありがとうございました!