2020年8月28日 星期五

C 語言 - 正規表示法實作 ( regex.h )

regex.h (Linux 原生, Windows 再說)

    Regex.h 實作主要分 3 階段,regcom, regexec, regfree。
    // 要被批配的 buffer 跟一些參數
    int status, len, i;
    char buf[1024], data[1024];
    getdata(data);

    // 正規表示式的會要先 compile (regcomp())並儲存在 regex_t 此資料結構
    regex_t preg;

    // 設定批配模式的 flag. 
    // REG_EXTENDED ERE (Extended Regular Expression, 不用就是 BRE)
    // REG_ICASE    忽略大小寫
    // REG_NOSUB    不儲存批配後的結果
    // REG_NEWLINE  識別換行符(^$ 這類符號會成每一行的開頭跟結尾), REG_NEWLINE 效力 > eflags
    int cflags = REG_EXTENDED | REG_NEWLINE;

    // 正規表示式的批配樣板
    const char * regex = "Name: ([A-Z a-z]+)\nYear of Birth: ([^\n]*)\n([^:]*: [^\n]*)";

    // pmatch 為 struct 陣列去儲存批配後的結果
    // pmatch.rm_so 批配到的子字串在 target string 的起始 index
    // pmatch.rm_eo 批配到的子字串在 target string 的終止 index
    // nmatch 為宣告 pmatch 的陣列大小
    const size_t nmatch = 10;
    regmatch_t pmatch[nmatch];
    
    // eflags 也會對批配做改動
    // REG_NOTBOL   開頭批配符號(^)永遠批配不到
    // REG_NOTEOL   結尾批配符號($)永遠批配不到
    // REG_STARTEND 是直接使用 pmatch[0] 的 rm_so 跟 rm_eo
    //   作為字串頭尾的 index 然後批配,是為了避免 target string 
    //   中間有終止符(\0) 或 字串太長 strlen() 會 fail.
    int eflags = 0;

    // compile regex 
    if( regcomp(&preg, regex, cflags) != 0 ) {
        puts("regex compile error!\n");
        return;
    }

    // 進行批配 status = 0 代表成功
    status = regexec(&preg, data, nmatch, pmatch, eflags);
    if (status == REG_NOMATCH) {
        printf("No Match\n");
    } else if (status == 0) {
        // pmatch[0] 所指的子字串會是整串
        // pmatch[1], pmatch[2]... 會是括弧裡 sub regex,通常拿來取真正想要的值
        for (i = 0; i < nmatch && pmatch[i].rm_so >= 0; ++i) {
            len = pmatch[i].rm_eo - pmatch[i].rm_so;
            strncpy(buf, data + pmatch[i].rm_so, len);
            buf[len] = '\0';
            printf("match %d :\n%s\n\n", i+1, buf);
        }
    }

    regfree(&preg);
    return;

測試資料 跟 結果

    測試資料
Name: JunYe
Year of Birth: 1993
Gender: Male
    結果
match 1 :
Name: JunYe
Year of Birth: 1993
Gender: Male

match 2 :
JunYe

match 3 :
1993

match 4 :
Gender: Male

Basic (BRE) and extended (ERE) regular expression

    在一些特殊字元處理不一樣, 請參考 GNU的說明
參考資料 :

2020年8月8日 星期六

英文歌詞翻譯 Jonathan Roy - Keeping Me Alive


You try to hold me down so I became a soldier
你想要控制所以我成為了戰士
Built up all theses walls and now I'm climbing over
監牢般的城牆如今我已越過
Those nasty bees are tempting me
那些令人惱人的念頭還在勸誘著我
Oh lord! But I ain't going back
主阿!我是不會回頭的
You take me for a fool (fool), that doesn't make me foolish
試圖讓我認知自己的愚笨,並不會使我變成真的笨蛋
Told me I was wrong (wrong), passion made you ruthless
試圖讓我認知自己的錯誤,這份情感只會讓你更無情。
Manipulate, it's just too late
試圖操弄一切,但已太晚
Oh lord! 'Cause I ain't going back no more
主阿!我再也不會回頭的
Your fueling of the flames gonna show you what I'm made of
你全心助長的這份火焰只會讓我更堅信自己
Breakin' every chain that you put on me
斷開所有你在我身上施加的枷鎖
You thought I wouldn't change but I grew on you
你以為我不會改變但我已然超越你
'Cause I will never be what you wanted
因為我永遠不會成為你的洋娃娃
This fire (this fire), this fire
這份火焰,這份情感
Is keeping me alive
只會讓我更深切地感受自我
Making me believe I couldn't do without you
想讓我相信沒有你我將會一事無成
Make it hard to leave you think it's all about you
想讓我相信我的世界只會繞著你旋轉而難以逃脫
You know I'll never be what you wanted
你知道我永遠不會成為你的洋娃娃
This fire (this fire), this fire
因為這份火焰,這份情感

I tried to get this weight off of my shoulders
試著甩開肩上所有的包袱
Built up all my strength I'm finally taking over
所以累積著力量,最後終於克服
Complicate, I don't appreciate
試著複雜一切,但我不苟同
Oh lord, 'cause I ain't going back no more
主阿!我再也不會回頭的

Your fueling of the flames gonna show you what I'm made of
你全心助長的這份火焰只會讓我更堅信自己
Breakin' every chain that you put on me
斷開所有你在我身上施加的枷鎖
You thought I wouldn't change but I grew on you
你以為我不會改變但我已然超越你
'Cause I will never be what you wanted
因為我永遠不會成為你的洋娃娃
This fire (this fire), this fire
這份火焰,這份情感
Is keeping me alive
只會讓我更深切地感受自我
Making me believe I couldn't do without you
想讓我相信沒有你我將會一事無成
Make it hard to leave you think it's all about you
想讓我相信我的世界只會繞著你旋轉而難以逃脫
You know I'll never be what you wanted
你知道我永遠不會成為你的洋娃娃
This fire (this fire), this fire
因為這份火焰,這份情感
Is keeping me alive
只會讓我更深切地感受自我
Keeping me alive, keeping me alive
讓我感受自己活著,自己的存在
This fire (this fire), this fire (is keeping me alive)
這份火焰,這份情感

Breakin' me, shakin' me, shapin' me
打擊我,動搖我,塑造我
Into what I never wanted, oh
試圖想讓我變成我所不願的
Breakin' me, shakin' me
打擊我,動搖我
Makin' my beatin' heart a little stronger
只會讓我更強烈活著

2020年7月20日 星期一

Linux - Shell Scripts (3) (pipe : grep)

管線命令 ( Pipe )

    管線命令是用 "|" 去連接,只要前一資料能變成 standard input。管線命令僅會處理 standard output,而不會處理 standard error output。下面用時下最夯的 MBTI 作的假資料。
index    name    MBTI
1        JunYe   ISTJ
2        JunYe   ISTP
3        JunYe   ESTP
4        JunYe   ESTJ
5        Mario   ISFJ
6        Mario   ISFP
7        Mario   ESFP
8        Mario   ESFJ
9        Joel    INFJ
10       Joel    INFP
11       Joel    ENFP
12       Joel    ENFJ
13       Joel    INTJ
14       Joel    INTP
15       Joel    ENTP
16       John    ENTJ
17       John    ESFP
18       Peter   ESFJ
19       Peter   INFJ
20       Peter   INFP
21       Peter   ENFP
22       Eva     ESTJ

基本管線命令 grep

    grep會在每一行找尋配對的字串,然後列出來。
$ bash pipeData.sh | grep "JunYe"
1        JunYe   ISTJ
2        JunYe   ISTP
3        JunYe   ESTP
4        JunYe   ESTJ
    加 -v 找每一行沒配對的字串,然後列出來。
$ bash pipeData.sh | grep -v "JunYe"
index    name    MBTI
5        Mario   ISFJ
6        Mario   ISFP
7        Mario   ESFP
8        Mario   ESFJ
9        Joel    INFJ
10       Joel    INFP
11       Joel    ENFP
12       Joel    ENFJ
13       Joel    INTJ
14       Joel    INTP
15       Joel    ENTP
16       John    ENTJ
17       John    ESFP
18       Peter   ESFJ
19       Peter   INFJ
20       Peter   INFP
21       Peter   ENFP
22       Eva     ESTJ
上一篇 :

2020年7月16日 星期四

Linux - Shell Scripts (2)

sh vs bash

    我有時候用 sh 會讓 shell script 執行不過,通常會報 Bad substitution 之類的錯誤。其實是因為我用 ubuntu,ubuntu 的 sh 其實是指到 dash 而非 bash。dash 在這不作多介紹, 把它想像成輕量型的 bash,所以支援的功能有限,所以有機會報錯。
ubuntu: cd /bin/
ubuntu: /bin$ ls -l
lrwxrwxrwx 1 root root       4  4月  9 16:36 sh -> dash

shell 字串操作

    #!/bin/bash
    # Shell 字串操作
    # 執行 bash string.sh

        file=/dir1/dir2/dir3/my.file.txt

        # 字串刪減
        # '#' 專刪右邊
        echo ${file#*/}   # 從左邊開始批配,刪掉 / 自身和其左邊的字串:dir1/dir2/dir3/my.file.txt
        echo ${file##*/}  # 從右邊開始批配,刪掉 / 自身和其左邊的字串:my.file.txt
        echo ${file#*.}   # 從左邊開始批配,刪掉 . 自身和其左邊的字串:file.txt
        echo ${file##*.}  # 從右邊開始批配,刪掉 . 自身和其左邊的字串:txt
        # '%' 專刪右邊
        echo ${file%/*}   # 從右邊開始批配,刪掉 / 自身和其右邊的字串:/dir1/dir2/dir3
        echo ${file%%/*}  # 從左邊開始批配,刪掉 / 自身和其右邊的字串:
        echo ${file%.*}   # 從右邊開始批配,刪掉 . 自身和其右邊的字串:/dir1/dir2/dir3/my.file
        echo ${file%%.*}  # 從左邊開始批配,刪掉 . 自身和其右邊的字串:/dir1/dir2/dir3/my

        # 取子字串
        echo ${file:0:5}  # 從 index 為 0 之字元,往後取 5 個:/dir1
        echo ${file:5:5}  # 從 index 為 5 之字元,往後取 5 個:/dir2

        # 字串取代
        echo ${file/dir/path}  # 將第一個 dir 取代成 path:/path1/dir2/dir3/my.file.txt
        echo ${file//dir/path} # 將全部的 dir 取代成 path:/path1/path2/path3/my.file.txt

    exit 0

shell 陣列操作

    # Array 操作

        declare -a ARRAY      # 宣告 array 可以省略
        ARRAY=(first second third)
        echo ${ARRAY[0]}      # first
        echo ${ARRAY[1]}      # second
        echo ${ARRAY[2]}      # third
        echo ${ARRAY[*]}      # first second third
        echo ${ARRAY[*]:1:2}  # second third
        echo ${ARRAY[@]:1:2}  # second third
        
    exit 0
上一篇 :
下一篇 :

2020年7月14日 星期二

Linux - Shell Scripts (1)

sh v.s source

    如果直接用 sh 執行 script,基本上就是開一個子程序去執行 script。所以父程序要獲得子程序的結果,通常都是靠著 export 解決 scope 的不同。若是使用 source 去執行 script,則是直接用本身程序去執行,所以本身與腳本享有共同 scope。更多請參考 : 鳥哥私房菜

基本的 variable & operator

    基本上 shell 的語法網路上有很多相關資料,這邊我想紀錄的是那些對於菜鳥不怎麼直觀的 variable & operator。而且其實我認為 shell 的精華就是在這些 variable & operator。
  • variable
        #!/bin/sh
            # 執行 : sh variable.sh a b c 
            echo $0         # script 本身
            echo $1 $2 $3   # 執行 script 時, 後面跟著的 arguments
            echo $#         # arguments 之總數
            echo $*         # 全部 arguments, 這個例子就是 a b c 
            echo $@         # 全部 arguments, 這個例子就是 a b c ($* $@ 應該有所不同, 不過我試不出來...)
            echo $?         # 上一個程式最後回傳值 (exit 0)
            echo $$         # 此 shell 的 pid
            echo $!         # 此 shell 最後執行的 background process 的 pid
        exit 0
  • operator
        #!/bin/sh
        # 執行 : sh operator.sh 20 10 
            
            # 此格式為固定的, ``, operator 前後要有空格
            # expr 不會檢查 $1 跟 $2, 所以沒有的話會出錯
            # 即使加了 "" 也會被判定 null, 等於 non-integer 也是錯 
            val=`expr $1 + $2`    # 相加
            val=`expr $1 - $2`    # 相減
            val=`expr $1 \* $2`   # 相乘 (*須加反斜線)
            val=`expr $1 / $2`    # 相除
            val=`expr $1 % $2`    # 取餘數
    
            # ==, !=, >, <, >=, <=
            if [ $1 = $2 ]; then
                val="equal"
            fi
    
            if [ $1 != $2 ]; then
                val="non-equal"
            fi
    
            if [ $1 -eq $2 ]; then
                val="equal"
            fi
    
            if [ $1 -ne $2 ]; then
                val="non-equal"
            fi
    
            if [ $1 -gt $2 ]; then
                val="greater than"
            fi
    
            if [ $1 -lt $2 ]; then
                val="less than"
            fi
    
            if [ $1 -ge $2 ]; then
                val="greater or equal"
            fi
    
            if [ $1 -le $2 ]; then
                val="less or equal"
            fi
        exit 0
  • 更多 operator
        #!/bin/sh
            # 執行 : sh operator2.sh 字串1 字串2 ...
            # 參數判斷時, 最好加上 "", 否則有高機率失效, 並出現 unary operator expected 等錯誤.
            if [ -z "$1" ]; then
                echo "there's no argument"
            fi
    
            if [ ! -z "$1" ]; then
                echo "there's at least one argument (!-z)"
            fi
    
            if [ -n "$1" ]; then
                echo "there's at least one argument (-n)"
            fi
    
            if [ "$1" ]; then
                echo "#1 argument is exist"
            fi
    
            # boolean operator -a = and, -o = or
            if [ "$1" -a "$2" ]; then
                echo "#1 and #2 arguments are both exist"
            fi
    
            if [ "$1" -o "$2" ]; then
                echo "there's at least one argument"
            fi
        exit 0
參考資料 :
下一篇 :

2020年7月11日 星期六

英文歌詞翻譯 Rudimental - These Days feat. Jess Glynne, Macklemore & Dan Caplen


I know you moved onto someone new
我知道你已經開始尋找新對象
Hope life is beautiful
希望你過得很好
You were the light for me to find my truth
你曾經是我追尋自我的燈塔
I just wanna say, thank you
現在我只想說 謝謝你

Leaving to find my soul
為了找尋真正的自我
Told her I had to go
告訴她我必須走了
And I know it ain't pretty
我知道這一點都不美好
When our hearts get broke
當彼此的心破碎
Too young to feel this old
還太年輕去體驗這殘酷的離別
Watching us both turn cold
看著兩個人漸行漸遠
Oh, I know it ain't pretty
我知道這一點都不美好
When two hearts get broke
當彼此的心破碎
Yeah, I know it ain't pretty
我知道這一點都不美好
When two hearts get broke
當彼此的心破碎

I hope someday
我希望有天
We'll sit down together
我們仍能坐在同一塊地方
And laugh with each other
一起暢談歡笑
About these days, these days
回憶曾經的時光
All our troubles
所有當初的不和
We'll lay to rest
我們都能釋懷放下
And we'll wish we could come back to these days, these days
讓我們甜蜜的回憶這段時光
These days, these days
那些時光
These days, these days
曾經的時光

Three years of ups and downs
經歷了三年的起起伏伏
Nothing to show for it now
現在卻一句話也說不出來
And I know it ain't pretty when the fire burns out
我知道這一點都不美好 當感情消逝殆盡
Calling me when I'm drunk, remind me of what I've done
在我沉浸酒精時數落我 一筆一筆算著我曾經錯誤
And I know it ain't pretty when you're trying to move on, yeah
我知道這一點都不美好 當你試著離開
I hope someday
我希望有天
We'll sit down together
我們仍能坐在同一塊地方
And laugh with each other
一起暢談歡笑
About these days, these days
回憶曾經的時光
All our troubles
所有當初的不和
We'll lay to rest
我們都能釋懷放下
And we'll wish we could come back to these days, these days
讓我們笑著回憶這段時光
Oh I know, I know
噢 我知道 我知道
Oh I know, I know
噢 我知道 我知道
Oh I know, I know
噢 我知道 我知道
These days, these days
這些時光 這些美好的時光
Oh I know, I know
噢 我知道 我知道
Oh I know, I know
噢 我知道 我知道
Oh I know, I know
噢 我知道 我知道
These days, these days
這些時光 這些美好的時光

Cigarettes in the ash tray
香菸靜靜地躺在菸灰缸裡
Reminiscing on those past days
回憶著那些日子
I thought you'd end up with my last name
我曾經以為你最終會是我的老婆
But that changed
但一切都變了
And I travelled around the world
我的足跡踏遍全世界
Think where you living at now?
卻想著你住在何方
I heard you moved to Oxford
我聽說你搬到 Oxford
Got an apartment and settled down
在一個公寓安頓下來
And every once in a while
每過段時間
I start texting
我就想著與你聯繫
Write a paragraph
但我寫了一個段落後
But then I delete the message
便停筆不寫了
Think 'bout you like a past time
像過往一樣地想起妳
I could cry you a river
我便淚流滿面
Get you baptised or
足以讓你沉浸在裡的那種
I wasn't ready to act right
我還沒準備好與你相遇
Used to always think I'd get you back, right
過去總想著挽回妳
They say that things fall apart (yeah)
他們說一切早已分崩離析
We were gonna move to Brooklyn
我們原本要一起搬到 Brooklyn
You were gonna study Art (oh no, oh)
妳原本要學藝術
Love is just a tool
原來愛情是一個工具
To remind us who we are
提醒著我們真正的自己
And that we are not alone
但現在我們已不孤單
When we're walking in the dark
當我們走在夜空下
備註 :
單身 30 年的我在聽到這首歌,腦中總會顯現那段不曾存在的戀情。這首歌送給有妄想症的單身狗。

讀書心得 - C++ Primer (5th Edition) - Chapter 2 (3) - Type Aliases



Type Aliases

    創造資料型態的同義詞,通常是用 typedef 來去實現。
    typedef double wages;   // wages is a synonym for double
    typedef wages base, *p; // base is a synonym for double, p for double*

auto

    寫程式常會有想要一個 variable 去儲存 expression 的運算結果,但要事先知道 expression 的最終資料型態非常困難。所以有 auto 這個特別的資料型態,讓編譯器決定其資料型態,但相對的 variable 一定要 initialize。
    auto item = val1 + val2; // item initialized to the result of val1 + val2
    因為 auto 一次只能當一個資料型態,所以在宣告時如果是用 ", " 分開的複數宣告,資料型態要一致。
    auto i = 0, *p = &i;      // ok: i is int and p is a pointer to int
    auto sz = 0, pi = 3.14;   // error: inconsistent types for sz and pi
    auto 與 const 的互動,基本上 auto 會忽視 top level const ( 物件本身為 const )。
    const int ci = i, &cr = ci;
    auto b = ci;       // b is an int (top-level const in ci is dropped)
    auto c = cr;       // c is an int (cr is an alias for ci whose const is top-level)
    auto d = &i;       // d is an int*(& of an int object is int*)
    auto e = &ci;      // e is const int*(& of a const object is low-level const)
    若想要個 top level auto const,你只能在 auto 前加 const 修飾詞。
    const auto f = ci; // deduced type of ci is int; f has type const int

decltype()

    不同於 auto,decltype() 可以不用去計算 expression,只讓編譯器去分析其資料型態。下面程式碼,編譯器不會呼叫 f(),而是去檢查 f() 的 return 資料型態去給予 sum。
    decltype(f()) sum = x;     // sum has whatever type f returns
    decltype() 也可以與 top level const 互動。
    const int ci = 0, &cj = ci;
    decltype(ci) x = 0;     // x has type const int
    decltype(cj) y = x;     // y has type const int& and is bound to x
    decltype(cj) z;         // error: z is a reference and must be initialized
上一篇 :

Popular Posts