[C/C++] Subtitle Merger

  • Subtitle Merger
  • Download:subMerger.cpp

    Subtitle Merger是一支筆者在幾年前突發奇想寫的程式,因為當時正好需要將兩個字幕合併成一個,所以就直接用C語言來寫一個簡單的字幕合併程式。而這一個小程式僅適用於.srt格式的字幕,所以如果你的字幕是.sub那我也就幫不上忙啦!簡單的介紹一下字幕的規格:

    在.srt的規格裡分成三類,index, time ,subtitle,每一個index之間間隔一行以上,且正常狀況下index是呈現遞增的成長,但是也有一些字幕很不守規矩,筆者我的程式沒有去處理例外規格的狀況,所以如果字幕不符合標準規格,用我的程式合併出來應該會出錯。

    既然有字幕合併那就會有字幕分割,分割的部份我沒有去實作,有興趣的人可以試試看。

[C/C++] Guess Number Game

  • Guess Number Game
  • 相信有不少人玩過猜數字遊戲,在看這一篇文章的你們甚至都寫過類似的程式,本篇並不是要著重在如何寫猜數字程式,而是把重心放在如何寫出一個較好的演算來判斷?A?B。完整的原始碼如下:

    Download: GuessNumber.cpp

    主要的核心演算程式碼如下:

    雖然這是一個很簡單的練習程式,且演算也很淺顯易懂,但是這裡面卻包含著一些重要的使用技巧,checkUserAns()這個程式是可以容許使用者或者正確答案內的數字有重複的狀況,使用了TableOfGuess,TableOfAns陣列分別紀錄玩家和正確答案的數字分佈情形,舉個例子來說,如果玩家猜測答案為1667,那TableOfGuess的數值會是如下:

    TableOfGuess[1]=1;

    TableOfGuess[6]=2;

    TableOfGuess[7]=1;

    其餘皆為0,透過這樣的儲存比較技巧我們可以很輕易的處理很多問題,這類的技巧筆者也是應用在上一篇的GP裡,使用array和index的特性,可以替代掉傳統的搜尋比對演算法所造成的低效率以及降低撰寫的複雜度。

    執行範例:

[EP/GP] random opponent

  • random opponent
  • 在EP(evolutionary programming)或者GP(genetic programming)裡,我們要過濾出在這個generation下較良好的strategies時,有可能會需要用到Tournament Selection(競爭式選擇),而在Tournament Selection裡,變動因子除了winner/loser的value assign,比較的先後之外(depends on your program),還有一個關鍵就是競爭者的選擇。

    舉個例子來說,假設我們要從10個strategies裡挑出5個較為優秀的作為下一代的parent,我們可能會亂數挑出3個給每一個strategy去做比較,最後再由比較後的得分高低決定誰要留下誰被淘汰。以下是一個tournament selection選擇實例:

    • 每一個generation裡有10個strategies。(5個是parent,5個是經由mutation後的child)
    • 每一個strategy要亂數挑出其他3個不重複的strategy做比較。
    • 經由一輪的比較之後,挑選top 5的strategy做為下一代的parent。

    當您的程式符合下述情況之後,做進一步的分析可能會發現,有些strategy被挑出來的次數可能是5次、6次,而有些卻只被挑出1次甚至0次(這樣的情形通常是你的亂數程式沒有規劃好),這樣的出現頻率差異,很有可能會破壞"適者生存,不適者淘汰"的理論,這時條件還要加上下面這一項:

    • 每一個strategy被選出來比較的次數皆為3。

    加上上面的條件之後,理論上tournament selection會更有效率。

    筆者為解決這個問題花了一些時間去產生符合上述情況的程式碼。如下:

    Download: ranOpp.c

    下載版的原始碼裡有完整的註解,這裡就講解主要的副函式- ranOpp().

    整個程式裡最關鍵的陣列變數就是connect,他紀錄著每個strategy跟其他strategy的關聯,假設strategy 0已經跟strategy 1比較過,那connect[0][1]就要設成非零數,所以在初始化過程時除了自己本身要設成1之外,其餘皆設成0,這樣就可以避免產生出的對手是自己的狀況。

    在程式碼27~33的初始化後,同一個col裡每一個元素(opp[0~9][col])都有一個唯一的數值,但是都是連續的,我們要透過上面的程式碼將他們的次序打亂,其中的while迴圈就是要避免兩數交換後,同一個row裡的元素數值跟row的值是一樣的,舉個例子來說,strategy 0的opp的數據如下:

    opp[0][0]=2

    opp[0][1]=2

    opp[0][2]=0

    可以看到opp[0][2]的值跟row的值是一樣的,所以程式會繼續再亂數挑選出其他strategy的值來做交換。也許你會有疑問,為什麼opp[0][0]跟opp[0][1]的值是一樣的,因為目前還只是初始化過程,我們還沒正式進入數字對調的主程式片段,也許你又會問那為什麼不將上面的檢驗方式直接整合到後面做處理,答案是可以的,只是如果沒有事先先排開,之後要花多一點心力去排除,也許你還是不懂我在說什麼,總之等你遭遇到錯誤時就會懂了。

    最外層的迴圈是col為主,因為我們的亂數組是以col為一個單位,而程式碼44~48是在檢查當前的opp[row][col]的值是否符合程式一開始的要求(不重複且不可為自己),同時在檢查完時不要忘記更新connect裡的數據,這時你又可能會問為什麼這些程式碼不在35~41行裡一起處理?不要忘了我們的程式是以col為主,每跑完一次後的次序會不一樣,所以不能在一開使就決定所有element的狀態。

    這部份就是整個程式的核心演算,因為我們並無法確定數值交換要換幾次,所以使用了while迴圈,當目前這個col內的所有element都check過了才跳出迴圈(程式碼69就是在做確認)。

    程式碼52行會先檢測當前的element符不符合規則,如果不符合就要進行亂數交換,也許你會覺得使用亂數交換會不會比較慢,尤其當strategy變很大時,難道就沒有一個比較有規則的交換方式嗎?答案是有的,只是如果要規則化就要分批處理,我想我們目前的集合都很小,一般的電腦足以負荷這種極小規模的亂數交換比對。

    例外還有一個很值得一提的就是為什麼connect裡的值不是設成1或0,而是遞增遞減,會這麼做的原因是因為我們的while迴圈的檢測只保證一方的值是合法的,但是卻無法保證另一方的值不會重複,例如strategy 5有下面三個對手

    NUMM(5) -> 0 1 1

    很顯然的strategy 5他有兩個strategy 1對手,這是不合法的,所以當他的第二個1被換掉時你會將connect[5][1]設成0還是connect[5][1]--?我想這樣解釋你應該很清楚為什麼要遞增遞減了。

    從頭到尾我都沒有提到說要如何避免strategy出現的頻率不一,但是在過程中我已經處理掉這個問題了,至於我是怎麼做的呢?我想讀者應該都已經發現,如果還是不了解,那就仔細的去觀察初始化的狀況,以及opp陣列的col值所代表的意義。

    以下是模擬數據,模擬10個strategy,分別挑出9個strategy對手出來。當然正常情況下不會有這種需求,就算有也不用用上面的麻煩寫法來產生。這個數據只是要驗證我們的程式是正確的。

    其實這個程式在邏輯上非常的單純,但有可能是筆者有一陣子沒有去寫GA的程式或者是random的程式要顧慮的條件較多,所以寫起來卡卡的,如果你有更好的方式也歡迎告知。

UTips. 40: chm viewer

  • chm viewer
  • 平常常見的電子文件格式除了pdf之外,還有一個型態的文件我們也常用到,chm(Compiled Help Manual),只是ubuntu在預設情況下是不會幫我們安裝支援chm格式的套件,你可以透過下面的指令來安裝即可閱讀chm的文件:

    • apt-get install gnochm

UTips. 39: PDF Printer

  • PDF Printer
  • 當我們會想要將文件轉換成pdf時,除了透過一些檔案轉換程式之外,還有一個常見的作法就是使用pdf printer,像是adobe acrobat等軟體都會有這類的附屬virtual printer,這裡提供一個ubuntu底下的pdf printer

    • apt-get install cups-pdf

    安裝完後到administration->printing->New Printer,設定新的應表機,這時你就會看到系統已經搜尋到一個"pdf printer",廠商選擇"Generic",型號選擇"PostScript" ,列印後的文件會在/home/你的帳號/PDF 裡。

UTips. 38: StarDict (alternative to Dr.eye)

  • StarDict (alternative to Dr.eye)
  • 一套不錯用的翻譯軟體。

    sudo apt-get install stardict

    安裝完主程式之後可以到下面的網站上去下載你要的字典,解壓縮後放置到/usr/share/stardict/dic這個資料夾重新啟動StarDict即可

    http://www.huzheng.org/stardict-iso/stardict-dic/

    語音檔下載的位置如下,解壓縮後放置到/usr/share裡,重新啟動stardict即可。

    http://sourceforge.net/projects/stardict/files/WyabdcRealPeopleTTS/

    執行範例如下:

    如果你不想要使用隨點即翻譯的功能,你可以把主程式的左下角那個scan按鈕取消掉即可。

UTips. 37: mimms (alternative to SDP)

  • mimms
  • 在ubuntu底下要下載mms串流的檔案可以安裝mimms:

    • apt-get install mimms

    這個程式是在terminal底下執行的,下載方式如下:

    • mimms mms://xxx.xxx.xxx

    下載後的檔案會在/home/你的資料夾,裡

[Flash] Working with Sound in AS2

  • Introduction
  • 接觸Flash好多年一直都沒有時間把所學寫成文件,這裡就先介紹一個類似C語言的Hello World!經典範例-Audio Player,這裡會用兩個範例來解說如何在Flash底下實現Audio Player,在進入主題之前讀者必須要有基礎的Flash設計能力才能了解範例內容。

  • Audio Player (Basic)
  • 設計環境如下:

    • Version: Flash MX or higher

    程式主架構圖如下:

    版面配置如下:

    由於這是一個非常簡單的例子,且筆者已經在兩年前發表過一篇關於startpage的設計文章,其中就有整合到flash music player,詳細部份可以參考Building Your Own Homepage Part-III

  • Audio Player (Advanced)
  • 設計環境如下:

    • Version: Flash MX or higher

    本程式除了結合基本的音樂播放功能之外,我還透過xml的結構來實現playlist的功能。

    程式主架構圖如下:

    程式在播放音樂時會從原本的單純讀取音樂的步驟變成如上圖的多步驟流程,猶如先前所提及的,當我們按下播放的按鈕時,程式會先向Server(mymusic.com)上尋求播放清單,程式解讀完播放清單上的曲目訊息後,再從這些音樂曲目選擇要播放的音樂,最後才向Server取得音樂會回傳到我們的網頁播放程式上。

    版面設計如下:


    整個播放程式的功能也提昇了許多,除了增加音量控制之外,還有播放進度、控制按鈕以及歌名顯示。僅用了兩個圖層(action,element),且將這兩個圖層包在一個MovieClip(Music Player),這樣的設計方便移植到其他專案上,至於各元件詳細的實體名稱請自行下載檔案參閱。

    在ActionScript的部份主要講解xml的部份,程式一開始要先初始化xml物件:

    我的xml檔案名稱為sndlist.xml,而核心的xml資訊讀取程式碼如下:

    直接看程式碼是有點難懂,所以我把我的XML結構轉成樹狀圖形結構:

    也許透過這樣的圖形化結構可以讓你更清楚的知道xml結構在flash裡要如何讀取。再我的XML程式讀取過程中,除了一一的把歌名和路徑分別存取到對應的變數之外,也在讀取後透過簡單的運算可以計算出總共有幾筆音樂,如此我的程式只需要修改sndlist.xml就可以增減曲目,而不必重新修正actionscript發佈新的swf。

    聲音控制的程式碼如下,使用了一個mouse listener來監控滑鼠的x座標位置來控制音量

    而進度顯示的程式碼跟音量控制有異曲同工之妙,也是取得滑鼠座標位置在轉化成百分比來控制音樂播放的位置:

    由於測試環境的限制以及Actionscript2.0本身功能的問題,筆者就不把demo放上來(請有興趣的人自行發佈測試),值得一提的是Music Player在進度的顯示上有一些問題,原因比較有可能是來自於Flash程式本身的錯誤,有時間的話我再重新以ActionScript 3.0撰寫然後放出來給大家參考啦!

UTips. 36: Java Runtime Environment (JRE) & J2SE Development Kit (JDK)

  • JRE & JDK
  • 不管你是要使用eclipse,或者是要安裝j-edit之類的軟體時,你都會需要使用到Java Runtime Environment,在ubutnut底下安裝JRE非常簡單,只需要打上下列的指令安裝即可:

    sudo apt-get install sun-java6-jre sun-java6-plugin sun-java6-fonts

    上面的package會一併幫你裝上plugin,fonts等套件。

    另外如果有需要開發JAVA程式時,也可以裝上JDK以便日後使用:

    sudo apt-get install sun-java6-jdk

    如果在編譯或執行過程中出現找不到檔案時,可以手動設定一下相關路徑。

    編輯下面的檔案

    sudo gedit ~/.bashrc

    然後加入以下幾行存檔後重新登入即可。

    PATH=$PATH:/usr/lib/jvm/java-6-sun/bin:/usr/lib/jvm/java-6-sun/jre/bin
    JAVA_HOME=/usr/lib/jvm/java-6-sun
    JRE_HOME=/usr/lib/jvm/java-6-sun/jre
    CLASSPATH=.:/usr/lib/jvm/java-6-sun/lib/tools.jar:/usr/lib/jvm/java-6-sun/lib/dt.jar export PATH
    export JRE_HOME
    export JAVA_HOME
    export CLASSPATH

[C/C++] dirent.h for windows

  • dirent.h for windows
  • 前面幾篇的介紹可能面讓許多人覺得linux底下的gcc能力很差,這裡要提一個windows底下沒有的功能。dirent.h函式的常用範例如下:

    這個範例是顯示當下目錄資料夾下所有的檔案目錄名稱,但是這樣一個例子在windows底下是無法編譯,這裡提供一個別人寫的Dirent API for Visual C++

    http://www.softagalleria.net/dirent.php

    同樣的例子其實也是可以透過system("dir /w"),system("ls -al")等語法來達成,只是要以處理檔案的方式來實現,詳細的使用範例有時間我再寫出來吧!

[C/C++] ++, -- operators

  • ++,-- operators
  • 下面是一個有趣的範例,不仿先不要看答案自己先想:

    以下是各編譯器編譯出來的答案:

    • VC++

      4 1 1

    • GCC

      6 4 1

    這樣的結果有可能會出乎你的預料之外,會有不同答案的原因是因為不同平台的編譯器編譯的方式不同,各編譯器轉成得組合語言如下:

    • AT&T Assembly

      使用gcc -S xxx.c方式編譯

    • Intel x86 Assembly

    • 使用VC++的cl -Fa xxx.c來編譯

    面對這樣的特性,以後寫程式要更加避免這樣的撰寫型態。

[C/C++] getch() for linux

  • getch() for linux
  • 在linux底下的gcc是不支援conio.h這個標頭檔,自然就不行使用getch()。這裡提供網路上一個簡便的實做getch()程式碼。

    #include <stdio.h>
    #include <termios.h>
    #include <unistd.h>

    int getch(){
        struct termios oldt, newt;
        int ch;
        tcgetattr( STDIN_FILENO, &oldt );
        newt = oldt;
        newt.c_lflag &= ~( ICANON | ECHO );
        tcsetattr( STDIN_FILENO, TCSANOW, &newt );
        ch = getchar();
        tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
        return ch;
    }

    int main(void)
    {
        getch();
        return 0;
    }

[C/C++] itoa() for linux

  • itoa() for linux
  • 我想很多人都無法理解,為什麼linux底下的gcc只支援atoi(),卻沒有itoa(),原因是因為itoa()並不是ansi規範裡的函式,但是在programming的過程中,我們往往會需要用到itoa()的功能來完成我們的需求,這時筆者我就只好寫一個類似itoa()的函式啦!這個版本只支援10進位,等到有其他需求筆者在將他寫成多進位吧!

  • 為了讓排版好看所以用圖形的方式呈現,並不是故意不讓你們直接複製,看不清楚程式碼可以點圖放大。

[C/C++] fflush() for linux

  • fflush() for linux
  • 在windows底下要清除螢幕,我們會用system("cls")或者是fflush(stdout),但是在linux底下就不能使用fflush(stdout),只好勉為其難的用以下方式取代(畢竟clear並沒有真的把畫面清空):

    除了上面常用的例子之外,fflush()也常在以下情況使用,如下程式碼:

    在windows底下這個程式可以正常的運作,但是一旦拿到linux底下編譯就會出現下面的結果:

    會有這樣的結果的原因是因為在linux底下fflush(stdin)是無效的,所以這時筆者我會以這樣的方式解決:

    使用fgetc(stdin),來吸收掉enter後多出的字元,這樣的作法固然有用,但是必須非常了解scanf(), fgetc(), fgets()等函式的特性去使用才不會產生別的錯誤。

[C/C++] system("pause") for linux

  • system("pause") for linux
  • 在windows底下如果不想藉由開發工具做debug時,筆者我多數使用system("pause")這個指令,但是一到了linux之後,這個指令完全無效,因為linux的termainl底下本來就沒有這個指令,面對這樣的問題,網路上有一堆解決方式,這裡提供筆者我自己常用的方法。

    方案一,範例如下:#include <stdio.h>
    #define PAUSE printf("Press Enter key to continue..."); fgetc(stdin);
    int main(void)
    {
        PAUSE
        printf("system(\"pause\") for linux!\n");
        return 0;
    }

    可以看到我只是簡單的使用兩個指令來達到一樣的效果,我還用#define給預先定義起來,如此一來我每次要使用只需要打上PAUSE即可。

    當然如果你夠懶的話,就把他寫成header file,以後要使用就載入header file來使用。

    方案二:
    直接產生一個類似pause的程式,然後把他放在/usr/bin裡面,pause的實做程式碼如下:#include <stdio.h>
    void main(void)
    {
        printf("Press Enter key to continue...");
        fgetc(stdin);
    }
    如此一來你就可以直接在程式碼裡使用system("pause");了。

    PS. fgetc()必須讀到Enter的keycode才會終止當下的輸入,如果你要達到完全的任意按鍵就執行下一行,可以[C/C++] getch() for linux

[GCC] GCC for Windows (MinGW/DEV-C++)

  • MinGW
  • 儘管windows底下有一個優秀的程式開發工具Visual Studio,但我還是要介紹MinGW這套優秀的編譯器。除了他是免費之外,再者就是如果你有unix programming的經驗,應該會清楚的了解到GCC(或者Dev-C++)與Visual Stduio中的差異。MinGW的官方網站如下:

    http://www.mingw.org/

    很多人一進到官方網站後卻不知道要下載什麼來安裝,筆者就直接把連接連出來,你只需要下載下面的東西回到你的電腦裡,接著按照指示安裝即可。

    MinGW-5.1.4.exe

    MinGW的使用方式跟Linux底下的GCC是完全一樣的。詳細使用方法請參照官方網站。

    安裝完後你就可以在cmd底下編譯程式,但是你會發現你無法像在linux底下一樣使用gcc來編譯,反而是要打全名(c:\MinGw\bin\gcc),你可以到控制台->系統->進階->環境變數去修改Path的值,如下圖:

    去編輯Path的值,在最後面加上;c:\MinGw\bin 如下圖:

    這樣大致上就設定完成了。

    gcj:

    如果你有安裝gcj,且想不開想用gcj做為編譯java的主要工具,那我建議你要裝liblconv for windows,這樣你才能夠編譯java(就目前的版本情況是如此),下載位置如下:

    http://gnuwin32.sourceforge.net/packages/libiconv.htm

    安裝完當然還是要設定一下,編譯過程中記得把libiconv的路徑加進去,否則他還是會告訴你找不到檔案,編譯完後記得將libiconv2.dll放在你的執行檔案同個目錄下(或者直接塞到system32底下),不然你又不能執行程式。

    所以真的覺得使用gcj很麻煩,那就使用jdk或者eclipse吧!

  • Dev-C++
  • 如果你覺得安裝和使用MinGW對你而言有困難,那你可以使用圖形化介面的編譯器Dev-C++,我想有不少人用過這個編譯器,但是卻不知道他是基於GCC核心所開發出來的軟體。

    可以到下面的地方下載:

    http://wxdsgn.sourceforge.net/

    這裡我提供的已經不是原先版本的Dev-C++,而是wxDev-C++開發團隊所接手的新版本,而wxDev-C++就是多了wxWidgets的功能,是一個可以開發出跨平台的程式套件。

    不管是安裝Dev-C++或者是MinGW,我都建議你們設定一下系統環境變數,將path的地方增加c:\Dev-cpp\bin(如果這是你的Dev-C++安裝路徑)。

  • CodeBlocks
  • CodeBlocks是一個跨平台的開發套件,他主要還是以支援wxWidget為主,如果你有安裝wxDevCpp,那你可以不需要再安裝CodeBlocks,有不少人推薦使用CodeBlocks。

    官方下載位置如下(記得下載含mingw的版本):

    http://www.codeblocks.org/downloads/binaries

    安裝完一樣要設定環境變數的路徑。

    如果你是linux用戶,裝完CodeBlocks之後卻無法啟動,顯示找不到libcodeblockXXX時,你可以編輯/etc/ld.so.conf這個檔案,並加上/usr/local/lib這個路徑存檔後,執行ldconfig即可。

  • CodeLite
  • 另一套跟CodeBlock很像的軟體,只是你必須從MinGW, GDB一路裝上去,說穿了你還是得自行裝MinGW。官方下載如下:

    http://codelite.org/LiteEditor/Download

    官方頁面上有安裝步驟,如果你對CodeLite有興趣的話。

  • Cygwin
  • 除了上述的幾套工具之外,最正統的就是cygwin,他會幫你在windows模擬出一個linux環境,然後你就可以在這環境下安裝gcc,此方法是最完全的配套方案,出問題的狀況最少,但是需要更多的設定步驟。官方下載位置如下:

    http://www.cygwin.com/

    這部份你就自行研究吧!

  • MinGw for Linux
  • 如果你是Linux用戶,且又想在Linux底下使用MinGW編譯Win32的程式時你也可以安裝MinGW for linux來解決這個問題,以ubuntu為例:

    • sudo apt-get install mingw32

    安裝完後編譯程式的時候改用下面的指令(假設我們要編譯一個叫做Hello.c的程式):

    • i586-mingw32msvc-gcc -o Hello.exe Hello.c

    其實只是把gcc改成i586-mingw32msvc-gcc而已,如果嫌檔名長你也可以寫成makefile來處理,至於makefile的撰寫部份下次再說吧!

UTips. 35: Kwrite

  • kwrite
  • 在gnome環境下我們在programming時通常就直接使用gedit或者bluefish,再不然就是emacs,但是上述的編輯器除了emacs之外,其餘編輯器都沒有針對assembly language做highlight,這時就只好借用kde環境下的kwrite啦!

    安裝方式如下:

    • apt-get install kwrite

    下圖是用kwrite來編輯mips組合語言的樣子。

Orange - data analysis tool

Installation pip install orange3 Run orange python -m Orange.canvas