2017年8月21日 星期一

C# - REGEX(Regular Expression)的運用技巧(地圖運用篇)

我寫程式寫到現在,我覺得演算法中要說最精華的,就應該是Regular Expression
Regex如果用的好,可以增進系統的效能,還可以達到程式的優化。
但其實Regex是一個不好學的東西,因為它沒有那麼的直覺,是真的需要花很多時間去了解。
下面我就來分享如何使用REGEX的技巧:

假設我們有個需求,是透過幾段字串裡面,編排出找尋位置的方法,例如下面的字串:

$MAP
  MAP "1"  1234
  MAP "2"  5678
  MAP "3"  9101 

$POSIITION 1234

  POSITION  "A2"  PARAM  "1"  "2"
  POSITION  "B4"  PARAM  "2"  "1"
  POSITION  "C1"  PARAM  "3"  "1"

$POSITION 5678

  POSITION  "D4"  PARAM  "1"  "2"
  POSITION  "E2"  PARAM  "2"  "1"
  POSITION  "F1"  PARAM  "3"  "1"

在第一行上面可以看到有一個MAP的關鍵字,它有一整行看起來很有規則的文字,然後下面的POSITION,我們就可以利用這一段的文字,來取出一些關鍵的參考:


//定義一個可變動的索引值
string num = "1";
Regex rgx = new Regex(@"\sMAP\s\s\w*""" + num + @"""\s\s\w*\s\s\w*\w*""\d""");

//然後我可以辦識的結果取出
Match match = rgx.Match(line);

if (match.Success)
{
    Console.WriteLine("Regex{0}", match.Value);

}

在上面的一段程式,透過REGEX的處理,我們可以取到一段像這樣的結果:



上面的一段@"\sMAP\s\s\w*""" + num + @"""\s\s\w*\s\s\w*\w*""\d"""

我們可以這樣解讀:

1.\sMAP\s\s:空白字元旁邊有一個MAP然後兩個空白字完。
2.\w*""" + num + @""":空白字元旁邊的"1"字元。
3.\s\s\w*\s\s\w*\w*""\d"":空白字元後面的字元。

這樣就可以搜尋到相關的字串,然後我們就可以把字串批配到另一段我們想要的參數上:

//如果找到符合的Keyword,就進入判斷
if (match.Success)
{
     string keysearch = match.Value;

        //透過REGEX取出想要的值
     rgx = new Regex(@"\sMAP\s\w*\""" + num + @"""\s\s");

        //把不要的部分取代
     string result = rgx.Replace(keysearch, "");
}

這樣就會找到我們要參數


我們就可以把剛剛的規則透過Function包起來,然後再去批對POSITION找到我們想要的結果。
這種技巧其實可以運用在很多的開發層面上,尤其是搜尋引擎,熟練這樣的寫法,可以寫出令人讚嘆的程式喔。

下面是我的範例下載,有興趣可以下載來研究看看:



https://code.msdn.microsoft.com/C-REGEX-Regular-Expression-a72e0208




-雲遊山水為知已逍遙一生而忘齡- 電腦神手

2017年8月20日 星期日

如何設計成JSON的字串TXT檔,然後透過讀取的方式轉換成物件

在開發遊戲專案時,有時候會用程式寫從TXT讀取來的一些格式,然後從中轉換成JSON的方式。
其實有很多的方法,像是載入CSVXML等,在這裡教一些比較簡單的一些寫法,可以知道要如何去做這樣的設計。

如何設計成JSON的字串TXT檔,然後透過讀取的方式轉換成物件。

1.建立介面上會用到的物件:
//按扭
public Button button1 = new Button();

//顯示結果的Label
public Label resultLabel =new Label();

2.主要初始化的Function

this.button1.Location = new System.Drawing.Point(8220);
this.button1.Name = "btn";
this.button1.Size = new System.Drawing.Size(12030);
this.button1.TabIndex = 1;
this.button1.Text = "Do CSV To JSON";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.click);
         
//初始化一個Label,等一下用來顯示結果用的
this.Controls.Add(this.button1);
this.resultLabel.Location = new System.Drawing.Point(1060);
this.resultLabel.Name = "label1";
this.resultLabel.Text = "";
this.resultLabel.AutoSize = true;
this.Controls.Add(this.resultLabel);

3.設計一個按扭的監聽程式,然後寫下可以呈現結果的程式邏輯:

//讀取csv檔,然後透過System.IO.File.ReadAllLines來讀取每一行的JSON String的格式
string[] lines = System.IO.File.ReadAllLines(@"csvfile.csv");

//在這邊透過foreach把一行的JSON取出
foreach (string line in lines)
{
       Console.WriteLine("JSON String{0}", line);
       this.resultLabel.Text += line+"\n\n";
             
              //轉換成JSON Object的格式
       Player pj = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<Player>(line);
             
            //Object裡的值取出來用,在Label上面編排結果
      this.resultLabel.Text += "JSON Object Id Value"+pj.Id.ToString()+"\n\n";
      this.resultLabel.Text += "JSON Object HP Value"+pj.HP.ToString()+"\n\n";
      this.resultLabel.Text += "JSON Object MP Value"+pj.MP.ToString()+"\n\n";
      this.resultLabel.Text += "JSON Object Skill Value"+pj.Skill.ToString()+"\n\n\n";
}

上面的csvfile.csv,雖然我是採用csv的副檔名,但是在我的範例上,還是用TXT方式去設計。
如果是CSV真正的格式,其實會略有不同,寫法上也要稍作改變,但是其實方式會差不多。
csvfile.csv的內容裡面,會看到看起來像是下面的字串,然後要一行一行的斷行:


{"Id":100,"HP":10,"MP":14,"Skill":"attack"}

裡面有IdHPMPSkill,然後在程式裡面我們定義一個名字叫Player的物件,裡面的變數也定義IdHPMPSkill(型態可以自定)

然後透過下面的這段程式碼作轉換:

System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<Player>(line);


當按扭按下後,就會顯示結果,我們就可以從Player上去使用Id, HP, MP, Skill






上面的範例其實是一個很基本的概念,它可以有很多的變化型式的寫法。
如果是要用CSV的格式,那就要將每一個JSON的字串加上逗點,然後在處理字串時用Split的方式轉成String Array,然後一樣放入Deserialize<Player>(your_string)裡面。

下面是程式碼範例下載,有興趣可以下載:




-雲遊山水為知已、逍遙一生而忘齡電腦神手

2017年8月14日 星期一

C# WPF - Linear Sequential Search Algorithm

演算法是在電腦工程裡面,我想有在寫程式的人,應該一定至少有聽過的名詞。

介紹一個常見的搜尋演算法-Linear Sequential Search,故名思意,就是循序的方式去找到相符的資料,很簡單的寫法,就是直接用迴圈去比對,找到時就回傳結果。

以下面的例子,在Console的視窗裡透過一長串不整的數字中,找尋到想搜尋的數字:

int val = -1for (int i = 0; i < list.Length; i++) 
{ 
    if (list[i] == item) 
    { 
        val = i; 
        break; 
    } 
} 
return val;


同樣的運用在WPF裡,也是可以同樣的操作方式去設計:

int val = -1for (int i = 0; i < list.Length; i++) 
{ 
    if (list[i] == item) 
    { 
        val = i; 
        break; 
    } 
} 
return value;

可以看到演算法的結果:

string _l = ""for (int j = 0; j < num.Length; j++) 
{ 
    _l = "Find the " + (j + 1) + " time(s) "; 
    for (int i = 0; i <= j; i++) 
    { 
        if (num[i] == search) 
        { 
            _l += num[i].ToString()+" "; 
            _l += "Got it"; 
            this.___TextBlock___.Inlines.Add(GetString(_l, "red")); 
            return; 
        } 
        else 
        { 
            _l += num[i].ToString()+" "; 
        } 
 
    } 
    _l += "\n"; 
    this.___TextBlock___.Inlines.Add(GetString(_l)); 
} 
 
_l += "Can't find it \n";

此方法不一樣的方法在於,它會將後面的結果略過不處理,減少系統的效能,這對於大量資料的搜尋,有很大的幫助。當然,它可以搭配像字串處理的演算。演算是一門必修的課程,可以多學幾招以後就會派上用場。


-雲遊山水為知已逍遙一生而忘齡- 電腦神手

2017年8月12日 星期六

Windows 8/8.1/10 下VirtualBox無法開啟虛擬化VT-x的解決方法

Windows 8/8.1/10 VirtualBox無法開啟虛擬化解決方法

目前此文章雖然是以Windows  8/8.1來寫的(因為當時Windows 8出來時就寫好了),不過在Windows  10下也是適用的,如果使用者有在Windows 10遇到此問題也可以相同方式處理。

Windows 8 & 8.1系統後,使用 VirtualBox後;導入之前的虛擬機器並啟動時,會出現提示出錯,出錯代碼如下:
Couldn't find the end of CPUID sub-leaves. (VERR_CPUM_TOO_MANY_CPUID_SUBLEAVES).
返回 代碼:E_FAIL (0x80004005)
組件:Console

介面:IConsole {8ab7c520-2442-4b66-8d74-4ff1e195d2b6}






並且,在Virtualbox新建虛擬機器的介面,只能新建32位元虛擬機器。
虛擬機器設置頁,硬體加速標籤灰色,無法啟用。
筆者第一感覺,判斷認為是Virtualbox的問題,卸載後重新以管理員身份安裝,問題依舊。

再次,檢查電腦設置,確認 BIOS中已經開啟虛擬化VT-x功能,如下圖:



發生問題的原因:
如果windows 8/8.1 下已經啟用 Hyper-V,需要關閉此功能。所以解決此問題的方法如下:

一、win+Q 打開 Hyper-V管理員:




檢查 Hyper-v管理服務狀態,停止此服務。



二、以系統管理員許可權啟動命令列

Win + X 打開快顯功能表,如下圖所示:



執行下列命令(此命令用來設置禁用 hyper-v)

 bcdedit /set hypervisorlaunchtype off




如果想再次啟用 hyper-v 的話,請運行下列命令:
bcdedit /set hypervisorlaunchtype auto
三、最後,一定要重新啟動電腦,以上的步驟設置才能生效。

正常設置好後,VirtualBox 就可以正確啟動硬體加速功能。如下圖:




另一個可能是在軟體本身,根據官方的消息 Virtualbox 4.3.8 以後的版本會解決此問題。


-雲遊山水為知已、逍遙一生而忘齡- 電腦神手

2017年8月9日 星期三

Visual Studio2013的伺服器總管連接SQLExpress 2014資料庫無法加入資料連結的解決方法


在Windows 8.1 安裝 VS2013 Ultimate Update 2 & SQL Express 2014

(安裝SQLEXPR_x64_CHT.exe & SQLManagementStudio_x64_CHT.exe &

 SSDT 2013 版本: 12.0.40403.0 )

在SQL Server 2014 Management Studio下可連接到預設的資料庫,編輯user資料庫.

但在vs2013的伺服器總管: "加入連接" 可選取到user的資料庫名稱,

並作"測試連線"--->ok! 但按下"確認"時,產生下列警告訊息:
--------------------------------------------------------------------------

無法加入資料連結.

無法載入檔案或組件 'Microsoft.SqlServer.Managememt.Sdk.Sfc,

Version=11.0.0.0,Culture=neutral,

PublicKeyToken=89845dcd8080cc91'或其相依性的其中之一,系統找不到指定的檔案。

上面遇到的情況解決的方式:

可能的情況是SQL Server SDK沒有安裝在正確的路徑,有可能是在安裝的過程中,出現了一些錯誤,但詳細的情形,還是要看當時安裝的訊息來判斷。
另一個情況是因為Visual Studio上你的專案安裝了不同package和載入的Reference(參考)導致版本上的衝突,建議可以先整理一下套件上的版本,再重新試看看。

SQL Profiler 如何判斷資料正確的被新增


直接切入正題(因為好像找不到梗來說笑)

是這樣的,在我生命中有人曾提問:

發生資料無法正常寫入Log Table的情況,開啟Profiler錄製。

SQL Profiler看到SQL:BatchCompleted  RowCounts=1,Error=0.

但是資料沒新增到Log Table,也沒記錄到Exception
SQL Profiler判斷資料被正確的新增的方法。

假設你是從SQL Profiler使用openrowset,那會有Transaction ID,如果直接新增資料的話,並不會有交易。假設語法是加入SELECT XACT_STATE() AS A, @@TRANCOUNT AS B,結果回傳值都為1,表示有起交易,但資料並沒有新增進去,那表示資料可能被rollback
所以可以加入判斷,如果XACT_STATE()的回傳值為1的話,就commit這筆交易。當此選項設定為 1 時,SQL Server 就會允許特定存取。當此選項未設定或設定為 0 時,SQL Server 就不允許特定存取。

另外在語法上,設定 SET ROWCOUNT 選項會使大部分 Transact-SQL 陳述式在受到指定資料列數影響之後停止處理。其中包括觸發程序。ROWCOUNT 選項不會影響動態資料指標,但它會限制索引鍵集和非感應式資料指標之資料列集。在使用這個選項時應該要特別小心。進行單次指派的陳述式,一律會將 @@ROWCOUNT 值設為 1。它不會傳送任何資料列給用戶端。

設置SET ROWCOUNT選項將使大多數Transact-SQL語句在已受指定數目的行影響後停止處理。這包括觸發器和INSERTUPDATEDELETE等資料修改語句。ROWCOUNT選項對動態游標無效,但限制鍵集的行集和不感知游標。使用該選項時應謹慎,它主要與SELECT語句一起使用。 
如果行數的值較小,則SET ROWCOUNT替代SELECT語句TOP關鍵字。SET ROWCOUNT的設置是在執行或運行時設置,而不是在分析時設置。

另一個可能性的假設你的語法中,如果要拿某次的@@ROWCOUNT來判斷的話,只能判斷一次,如果要判斷多次的話,就要先把@@ROWCOUNT的值存到LOCAL變數,再去判斷這個LOCAL變數,才不會每RUN一個SQL,就會影響到@@ROWCOUNT的值。所以簡單的說它可能已經是預設在為1的情況下,但是可能你Log Table並沒有寫入任何的資料。



-
雲遊山水為知已逍遙一生而忘齡- 電腦神手

2017年8月8日 星期二

ORA-12705: Cannot access NLS data files or invalid environment specified(ORA-12705 Oracle連線時出現錯誤)


Visual Stuido開發的人,也許會有機會在工作上是搭配Oracle的資料庫(在江湖上,各種可能性都有的,別意外),這時如果對Oracle不熟的人,最常遇到下列的問題:

常見錯誤訊息(一):
ORA-12705: Cannot access NLS data files or invalid environment specified.
ORA-12705:語系設定錯誤。
regedit\HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE下找到NLS_LANG機碼予以刪除就可以。
出現ORA-12705的錯誤訊息,原因是NLS_LANGregedit機碼值是NA
為語系的編碼,有可能是電腦上安裝了Oracle Client後又移除所遺留下來的.
因此只要在regedit\HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE下找到NLS_LANG機碼予以刪除就可以。
在環境變數中加一項:NLS_LANG , 值:SIMPLIFIED CHINESE_CHINA.ZHS16GBK

常見錯誤訊息(二):
Oracle Instant Client ORA-12705 錯誤.
Oracle 即時用戶端設定異常ORA-12705
問題使用Oracle Instant Client 出現 ORA-12705: Cannot access NLS data files or invalid environment specified 錯誤。
如果是Windows平臺,註冊表裡 \HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE 查找鍵 NLS_LANG,這個鍵由Oracle標準用戶端安裝創建值是 NA 。這個導致了 ORA-12705錯誤。解決方法就是改名 NLS_LANG

其它設定:
CMD下這指令設定,要先設定Win環境變數,之後下指令可以設定語系,下面是例子,可以自行Oracle官方查詢:

C:\>set NLS_LANG=TRADITIONAL CHINESE_TAIWAN.ZHT16MSWIN950


-雲遊山水為知已逍遙一生而忘齡- 電腦神手