2014年9月22日 星期一

在 Blogger 上顯示 GitHub Ribbon

首先,到 GitHub Ribbons 挑選喜歡的配色,抄下其中 srcdata-canonical-src (非必要) 屬性。

在部落格的「版面配置」中,捲動到最後面,找到「新增小工具」,確認它是在「網誌文章」的後面,點選後,選擇「HTML/JavaScript」,然後插入下面程式碼:

  <script>
//<![CDATA[
/* Add GitHub Ribbons */
(function(options) {
  var el, href, pos;

  if (location.pathname==='/') {
    href = options.home;
  }
  else {
    el = document.querySelector('*[data-forkme]');
    if (el) {
      href = el.getAttribute('data-forkme');
    }
  }
  pos = options.position || 'right';
  if (href) {
    el = document.createElement('div');
    el.innerHTML = '<a href="' + href + '"><img style="display: block; position: fixed; top: 0; ' + pos + ': 0; border: 0; background:none; border-radius:0; box-shadow:none; padding:0; z-index: 9999;" src="' + options.src + '" alt="Fork me on GitHub" data-canonical-src="' + options.canonicalSrc + '"></a>';
    el.style.cssText = 'padding:0; margin:0; background-color:none;';
    document.body.appendChild(el);
  }
})({
  home: 'https://github.com/amobiz',
  src: 'https://camo.githubusercontent.com/e7bbb0521b397edbd5fe43e7f760759336b5e05f/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f677265656e5f3030373230302e706e67',
  canonicalSrc: 'https://s3.amazonaws.com/github/ribbons/forkme_right_green_007200.png',
  position: 'right'
});
//]]>
</script>

記得將最後面的 home 改為你自己的 GitHub 的個人頁面,並且分別填入剛剛抄下的 srcdata-canonical-srcsrccanonicalSrc 屬性中。彩帶預設放在右邊,如果挑選的彩帶必須放在左邊,則要加上 position: 'left' 屬性。

這樣設定之後,在部落格的首頁就會出現「Fork me on GitHub」的彩帶,點擊後會連到你的 GitHub 個人首頁。

預設在文章中不顯示彩帶。若要在文章中連到個人首頁或特定的專案,只要在文章的任意 HTML 標籤中,埋入 data-forkme 屬性,即可顯示彩帶:

  <div data-forkme="https://github.com/amobiz/lazy-umd.js"></div>

2014年9月20日 星期六

Lazy-umd.js - 懶人 UMD (Universal Module Definition)

最近在整理過去寫的程式庫,想要統一支援 script loader,同時又很貪心地想要:

1.同時支援 AMD(RequireJS)、CommonJS(node.js) 及 browser,解決不同語法差異。
2.模組套用時,避免修改 script loader 程式碼的需要。

研究了一下,發現 Addy Osmani 已經寫了 UMD。UMD 可以滿足第一點,但是應該是為了避免 script loader 程式碼擁腫,所以套用的時候,一定要修改 script loader 的部分。所以我自己整理出兩種做法,放在 GitHub 供大家參考:

2014年9月7日 星期日

將 SVN Local Repository 轉換為 Git Local Repository (Windows)

如果有舊專案使用 Subversion 管理程式碼,而且不是儲存在 svn server 上,而是使用 TortoiseSVN 的 create repository here 指令所建立的 repository。或者是 server 已不復存在,只剩下 repository 目錄的備份,那麼可以試著使用本文介紹的方式,轉換為 git 格式。

2014年8月5日 星期二

為什麼我要開發 Regular Expression Generator - RegexGen.js

RegexGen.js is a JavaScript Regular Expression Generator that helps to construct complex regular expressions.

如同我在 Regular Expression 學習筆記 所說明的:「學習 regular expression 的關鍵,不在於記憶簡寫符號,而是對引擎匹配原理的掌握。」最佳的 regular expression 學習方法,就是先學習正則引擎的匹配原理。想要快速查閱重點的話,可以參考前三篇學習筆記: (1), (2), (3),如果有充足的時間的話,當然還是建議詳閱 Mastering Regular Expressions 這本書。

然而,畢竟正則表達式的語法相當緊湊,想要一眼看懂複雜的表達式,幾乎是不可能的。首先必須熟悉正則表達式的 meta-character (元字元),然後一步一步拆解。雖然有 RegexBuddy 這樣的軟體可以幫忙拆解,但即使能正確的拆解,也可能無法了解作者 (通常是自己) 原本的思考邏輯,或者要避免的問題。

Regular Expression (JavaScript) 學習筆記 (3) - Informal BNF 語法

Informal BNF of Regular Expression of JavaScript (語法篇)

能夠找得到的 regular expression 的 BNF 語法不太多,以下是自己整理的 JavaScript 的 regular expression 的非正式語法,是依照自己的理解與體會所整理出來的,一定有許多錯誤、遺漏以及命名不當的地方,但還是把它列出來,幫助自己快速複習目前已掌握的 regular expression 的完整語法。讀者如果發現有任何錯誤或是有更好的表示方式,請不吝多多指教。

Regular Expression (JavaScript) 學習筆記 (2) - 原理篇 (下)

前言

上一篇介紹了正則引擎的基本功能與原理,接下來介紹功能更為強大的 lookaround (環視)。

Lookaround (環視) 不會佔用匹配字元

有時候,要匹配的文本主體,需要滿足的條件不只一個;或者,需要對上下文進行多重約束。

然而,對於一般的表達式而言,一旦文本匹配成功,便會由表達式所佔有;也就是說,同一段文本,絕不可能同時由兩個表達式所匹配。

另一方面,有時候,需要確保匹配的文本主體不含特定的內容,但是這個特定的內容,不是一個單一字元。在單一字元的情況下,我們可以使用否定型字元組來處理。但是在多重字元的情況下,卻很難使用一般的表達式辦到。

在這樣的需求下,許多新的 flavor (流派) 開始支援 lookaround (環視) 的功能。

對於環視表達式,最重要的特性就是,它們不會 consume (吃掉) 任何字元:不論匹配結果是否成功、不論是肯定型還是否定型、不論是順序還是逆序,引擎都會回到開始匹配前的原點,並且丟棄所有匹配的內容以及過程中儲存的備選狀態。在此之後,引擎才會根據環視表達式的匹配成功與否,進行下一個動作:當匹配成功時,引擎由目前位置繼續下一個表達式的匹配;當匹配失敗時,引擎回溯 (請參考前面回溯的說明) 到上一個儲存點 (這是由上一個表達式所儲存),繼續由上一個表達式儲存的下一個選擇進行嘗試 (或繼續回溯到上上個表達式)。

(環視使用的是一種擴展的 NFA:NFA-λ (也叫做 NFA-ε 或有 ε 移動的 NFA),它允許轉換到新狀態的變換不消耗任何輸入符號。)

可以這樣想像,lookaround (環視) 就像是站在原地不動,向前或向後觀望。依照環視檢視文本的方向,可以區分為 lookahead (順序環視) 和 lookbehind (逆序環視)。

Regular Expression (JavaScript) 學習筆記 (1) - 原理篇 (上)

前言

過去初學 regular expression 時,看了許多入門教學及參考資料,但多數資料幾乎都只是將一些表達式符號一一列出,然後再舉一些無關緊要的範例,以為這樣就可以弄懂 regular expression 了。做為初學者,看到這麼多的表達式符號,就以為 regular expression 很難學。直到看了 Mastering Regular Expressions 這本書,才知道其實是被誤導了。雖然 regular expression 提供了許多簡寫符號,但是大多數的簡寫符號多半只是為了縮短表達式的長度,這些簡寫符號只要在使用的時候查一下,實際使用過就可以熟悉了,根本不需要特別花時間記憶。其實學習 regular expression 的關鍵,不在於記憶簡寫符號,而是對引擎匹配原理的掌握。

正則表達式

正則表達式是強大、極富彈性、高效的文本處理工具。

其通用的模式表示法,具有如同迷你程式語言般的功能,賦予使用者描述和解析文本的能力。 配合上特定工具提供的支援,正則表達式能夠添加、移除、分離 (isolate)、疊加 (fold)、插入 (spindle) 和截斷 (mutilate) 各類型的文本和數據。

完整的正則表達式是由兩類不同的字元構成,特殊字元是由 *, +, ?, ^ 之類的字元構成,稱為 metacharacters (元字元),其餘的字元稱為 literal (文本字元) 或是 normal text characters (普通文字字元)。 可以把 metacharacters 想像為程式語言中的 operator (運算子),而 literal 則是 operand (運算元)。 (事實上,literal 本身也應該算是 operator: literal 中的每個字元,都代表必須匹配一個字元,而且是逐字元匹配。)

完整的正則表達式是由如上述的小的建構模塊單元組成。每個單獨的建構模塊都很簡單,過它們能夠以無窮多種方式組合,要將它們結合起來實現特殊目標,則必須依靠經驗。

2014年7月4日 星期五

Open Sourced my JavaScript Regular Expression Generator - RegexGen.js

Hi there, I've open-sourced my new library, RegexGen.js, a JavaScript regular expression generator, please give it a try. Comments and issue reports are welcome. Thank you!

RegexGen.js - JavaScript Regular Expression Generator

RegexGen.js is a JavaScript Regular Expression Generator that helps to construct complex regular expressions, inspired by JSVerbalExpressions.

RegexGen.js is basically designed for people who know how the regular expression engine works, but not working with it regularly, i.e., they know how to make the regex works but may not remember every meta-characters that constructs the regex.

RegexGen.js helps people don't have to remember: meta-characters, shortcuts, what characters to escape and tricks about corner cases.

RegexGen.js helps reusing regex patterns. (checkout the [Matching an IP Address] example bellow.)

The Problems

RegexGen.js try to ease two problems.

  1. While creating a regular expression, it's hard to remember the correct syntax and what characters to escape.
  2. After done creating a regular expression, it's hard to read and remember what the regex do.

The Goals

RegexGen.js is designed to achieve the following goals.

  1. The written codes should be easy to read and easy to understand.
  2. The generated code should be as compact as possible, e.g., no redundant brackets and parentheses.
  3. No more character escaping reguired (except '\', or if you use regex overwrite.)
  4. If the generated code is not good enougth, bad parts can be easily replaced directly in the written codes.

Getting Started

The generator is exported as a regexGen() function.

To generate a regular expression, pass sub-expressions as parameters to the regexGen() function.

Sub-expressions as parameters which are separated by comma are concatenated together to form the whole regular expression.

Sub-expressions can either be a string, a number, a RegExp object, or any values generated by the owned functions of the regexGen() function object, i.e., the regex-generator() as the following informal BNF syntax.

Strings passed into the regexGen(), the text(), the maybe(), the anyCharOf() and the anyCharBut() functions, are always escaped as necessary, so you don't have to worry about which characters to escape.

The result of calling the regexGen() function is a RegExp object.

The basic usage can be expressed as the following informal BNF syntax.

  
RegExp object = regexGen( sub-expression [, sub-expression ...] [, modifier ...] )

sub-expression ::= string | number | RegExp object | term

term ::= regex-generator() [.term-quantifier()] [.term-lookahead()]

regex-generator() ::= regexGen.startOfLine() | regexGen.endOfLine()
    | regexGen.wordBoundary() | regexGen.nonWordBoundary()
    | regexGen.text() | regexGen.maybe() | regexGen.anyChar() | regexGen.anyCharOf() | regexGen.anyCharBut()
    | regexGen.either() | regexGen.group() | regexGen.capture() | regexGen.sameAs()
    | regex() | ... (see regexGen.js for all termGenerator()s.)

term-quantifier() ::= .term-quantifier-generator() [.term-quantifier-modifier()]

term-quantifier-generator() ::= term.any() | term.many() | term.maybe() | term.repeat() | term.multiple()

term-quantifier-modifier() ::= term.greedy() | term.lazy() | term.reluctant()

term-lookahead() ::= term.contains() | term.notContains() | term.followedBy() | term.notFollowedBy()

modifier ::= regexGen.ignoreCase() | regexGen.searchAll() | regexGen.searchMultiLine()

Please check out regexgen.js and wiki for API documentations, and check out test.js for more examples.