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.

2013年12月28日 星期六

整合 Maven 與 Yeoman, 學習筆記(5) - 使用 build-helper-maven-plugin 支援多 src 目錄

使用 build-helper-maven-plugin 支援多 src 目錄

對於一些較複雜的專案, 為了明確區分不同類型的 source code, 要求將它們分別放在專屬的目錄下. 譬如將 model, view, controller 分開來放. Maven 預設的 maven-compiler-plugin 只允許單一 source 目錄, 因此無法支援這樣的設定. 這時候, 就可以利用 build-helper-maven-plugin 來支援多 src 目錄 (不過官方並不推薦使用這種方法):


<!-- multi src dir support -->
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <version>1.8</version>
    <executions>
        <execution>
            <id>add-source</id>
            <phase>generate-sources</phase>
            <goals>
              <goal>add-source</goal>
            </goals>
            <configuration>
                <sources>
                    <source>src/main/rs-app/services</source>
                    <source>src/main/rs-app/domain</source>
                    <source>src/main/rs-app/resources</source>
                </sources>
            </configuration>
        </execution>
    </executions>
</plugin>


參考資料:

整合 Maven 與 Yeoman, 學習筆記(4) - tomcat-maven-plugin

支援 Tomcat 啟動

如果偏好使用 Tomcat, 為方便在 deploy 前直接啟動 web app 檢視, 可以在 pom.xml 加入 tomcat-maven-plugin, 引用的版本最好在 properties 區塊定義, 方便更新:


  <properties>
    <tomcat.version>2.2</tomcat.version>
  </properties>
      
  <build>
    <plugins>
      <!-- Tomcat support -->
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>${tomcat.version}</version>
        <configuration>
            <path>/</path>
        </configuration>
      </plugin>
    </plugins>
  <build>


  1. 跟 Jetty 相反, Tomcat 預設的 web app context 是 /${project.artifactId}, 以此範例來說就是 /myapp, 所以最好指定 path 參數. 參考 Tomcat 文件: Usage.
  2. 全部的 goal 參考 Plugin Documentation.
  3. 參數: Guide to Configuring Plug-ins. 沒有找到類似 Jetty 的 scanIntervalSeconds 參數.

然後, 這樣啟動:


  mvn tomcat7:run


相關文章:
參考資料:

整合 Maven 與 Yeoman, 學習筆記(3) - jetty-maven-plugin

支援 Jetty 啟動

為方便在 deploy 前直接啟動 web app 檢視, 可以在 pom.xml 加入 jetty-maven-plugin, 引用的版本最好在 properties 區塊定義, 方便更新:


  <properties>
    <jetty.version>9.0.6.v20130930</jetty.version>
  </properties>
      
  <build>
    <plugins>
      <!-- Jetty support -->
      <plugin>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>${jetty.version}</version>
        <configuration>
          <scanIntervalSeconds>10</scanIntervalSeconds>
          <webApp>
            <contextPath>/</contextPath>
          </webApp>
        </configuration>
      </plugin>
    </plugins>
  <build>


這裡使用 scanIntervalSeconds 參數啟動自動掃描, 方便修改時自動重新載入.

contextPath 則是指定 web app context, / 就是預設值, 所以可以省略, 此時 app 在 http://localhost:8080/ 啟動.

若指定為 /myapp, 則 app 在 http://localhost:8080/myapp/ 啟動.

啟動指令:


  mvn jetty:run


jetty:run goal 會自動觸發 build 階段, 不過若專案有經過大修改(譬如更動 class, method 名稱), 最好先 clean 再執行.

相關文章:
參考文章:

2013年12月27日 星期五

整合 Maven 與 Yeoman, 學習筆記(2) - 使用 mvn archetype:generate 建立 JAX-RS / Jersey 專案

建立整合專案時, 可以使用 Maven 的 template 機制, 建立需要的專案架構. 這時候可以執行 mvn archetype:generate 指令, 從中選取適合的範本. 執行該指令時, 若不指定 filter 或 archetypeGroupId 及 archetypeArtifactId 參數, 會進入 interactive mode, Maven 會列出在中央倉庫中所有的 archetypes, 目前有 800 多個範本可選.

建立 JAX-RS / Jersey 專案

根據 Jersey - Download 的說明, 可以執行 mvn archetype:generate 指令:


  mvn archetype:generate \
            -DarchetypeGroupId=org.glassfish.jersey.archetypes \
            -DarchetypeArtifactId=jersey-quickstart-webapp \
            -DarchetypeVersion=2.5


快速建立 jax-rs web app. 由於省略 -DarchetypeVersion=2.5 參數時, Maven 會自動選擇最新的版本, 所以其實只需要這樣:


  mvn archetype:generate \
            -DarchetypeGroupId=org.glassfish.jersey.archetypes \
            -DarchetypeArtifactId=jersey-quickstart-webapp


若是不想進入互動模式, 也可以直接指定 groupId, artifactId, version, package 參數, 然後指定 -DinteractiveMode=false 參數, 進入 batch mode, 譬如:


  mvn archetype:generate \
            -DarchetypeGroupId=org.glassfish.jersey.archetypes \
            -DarchetypeArtifactId=jersey-quickstart-webapp \
            -DgroupId=com.github.myapp \
            -DartifactId=myapp \
            -Dversion=1.0.0-SNAPSHOT \
            -Dpackage=com.github.myapp \
            -DinteractiveMode=false


自行建立 archetype

若經常需要重複建立類似的專案, 也可以考慮自行建立 archetype. 等有空的時候再來試試看.

參考文件: Guide to Creating Archetypes.

後記

Yeoman 的 GETTING STARTED WITH YEOMAN 文件上說:

On Windows, we suggest you use an improved command line tool such as Console2 or PowerShell to improve the experience.

但我使用 Windows PowerShell 來執行指令:


  mvn archetype:generate
            -DarchetypeGroupId=com.sun.jersey.archetypes
            -DarchetypeArtifactId=jersey-quickstart-webapp


會出現錯誤訊息:

The goal you specified requires a project to execute but there is no POM in this directory

後來發現把參數用引號刮起來, 像這樣:


  mvn archetype:generate
            "-DarchetypeGroupId=com.sun.jersey.archetypes"
            "-DarchetypeArtifactId=jersey-quickstart-webapp"


才能正確執行. 由於不熟 PowerShell, 暫時還不清楚原因. 目前還是使用 cmd 來建置專案.

歡迎大家的回饋與心得分享.

相關文章:

參考文章: