Regular expression in common use

剛好要用到,所以特別在網路上找,主要都是給 RegularExpressionValidator 作 validate 用的…

  • 檢查日期
    • dd/mm/yyyy
      ((([0][1-9]|[12][\d])|[3][01])[-/]([0][13578]|[1][02])[-/][1-9]\d\d\d)|((([0][1-9]|[12][\d])|[3][0])[-/]([0][13456789]|[1][012])[-/][1-9]\d\d\d)|(([0][1-9]|[12][\d])[-/][0][2][-/][1-9]\d([02468][048]|[13579][26]))|(([0][1-9]|[12][0-8])[-/][0][2][-/][1-9]\d\d\d)
    • yyyy/mm/dd
      ([1-9]\d\d\d[-/]([0][13578]|[1][02])[-/](([0][1-9]|[12][\d])|[3][01]))|([1-9]\d\d\d)[-/]([0][13456789]|[1][012])[-/](([0][1-9]|[12][\d])|[3][0])|([1-9]\d([02468][048]|[13579][26])[-/][0][2][-/]([0][1-9]|[12][\d]))|([1-9]\d\d\d[-/][0][2][-/]([0][1-9]|[12][0-8]))
  • 限制位數的數字
    (^-?\d{1,10}\.$)|(^-?\d{1,10}$)|(^-?\d{0,10}\.\d{1,9}$)
  • 一般數字
    ^(-)?\d+(\.\d\d)?$
  • 檢查 e-mail
    ^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$
  • 查 url
    ^(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\’\/\\\+&%\$#_]*)?$

參考資料:

ANTLR 與 c#

ANTLR是一個用來將剖析語法轉換成語言的工具,如果你接觸過 lex/yacc 的話,就可以很容易瞭解.
這裡有一篇相當簡單的Introduction.
Step by step, 就可以做出一個計算運算式的小程式.
可是,產生出來的程式語言卻是 java, 如果要改用 c# 呢??
依照官方的說明, ANTLR 可以產出三種語言: C++, Java, c#.
所以該怎麼產生呢??需不需要另外寫甚麼??
官方網站同樣也提供了這麼一篇:Notes for using the ANTLR C# Code Generator.
這裡我們以Introduction裡面所提供的範例來作為例子,將他命名為 “expr.g.txt”:

class ExprParser extends Parser;
expr returns [int value=0]
{int x;}
: value=mexpr
( PLUS x=mexpr {value += x;}
| MINUS x=mexpr {value -= x;}
)*
;
mexpr returns [int value=0]
{int x;}
: value=atom ( STAR x=atom {value *= x;} )*
;
atom returns [int value=0]
: i:INT {value=Integer.parseInt(i.getText());}
| LPAREN value=expr RPAREN
;
class ExprLexer extends Lexer;
options {
k=2; // needed for newline junk
charVocabulary=’\u0000′..’\u007F’; // allow ascii
}
LPAREN: ‘(‘ ;
RPAREN: ‘)’ ;
PLUS : ‘+’ ;
MINUS : ‘-‘ ;
STAR : ‘*’ ;
INT : (‘0’..’9′)+ ;
WS : ( ‘ ‘
| ‘\r’ ‘\n’
| ‘\n’
| ‘\t’
)
{$setType(Token.SKIP);}
;

第一步你需要做的,就是在這份例子的最上頭加上

options {
language = “CSharp”;
namespace = “SmallCalc”; // encapsulate code in this namespace
//classHeaderPrefix = “protected”; // use to specify access level for generated class
}

表明我們要使用 c#, 並且 namespace 要命名為 SmallCalc.
接著使用下載到的 antlr, 來進行轉換
>antlr expr.g.txt
他會產出下列檔案:

  • ExprLexer.cs
  • ExprParser.cs
  • ExprParserTokenTypes.cs
  • ExprParserTokenTypes.txt

ok, 該有的都有啦,我們接下來需要的是主程式與必要的 antlr assembly(組件).
要取得 antlr assembly, 你必須先取得 antlr 的原始碼 (找 source distribution).
解開原始碼以後,在 lib/csharp/ 下,會有個 visual studio project 檔與 NAnt build 檔.
看你熟悉哪一個,就用哪一個.
總之你會得到 antlr.runtime.dll, 將他複製到剛剛程式所在的位置.
主程式的話,很簡單,就是使用剛剛產生出來的程式來進行剖析:

using System;
using System.IO;
using antlr;
namespace SmallCalc
{
public class Smallcalc {
public static void Main(String[] args)
{
ExprLexer lexer = new ExprLexer( Console.OpenStandardInput() );
ExprParser parser = new ExprParser(lexer);
int x = parser.expr();
Console.WriteLine(x);
}
}
}

然後編譯
>C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\csc /target:exe /out:smallcalc.exe /r:system.dll /r:antlr.runtime.dll *.cs
你會發現有點小錯誤:

ExprParser.cs(156,11): error CS0246: 找不到型別或命名空間名稱 ‘Integer’ (您是否遺漏 using 指示詞或組件參考?)

稍微調整一下,從原來的

value=Integer.parseInt(i.getText());

修正為

value=Convert.ToInt32( i.getText() );

再重新編譯一次,就大功告成了.
試試看結果囉…

>smallcalc
1+3+5+7*100
709

🙂
參考資料:

樂透下期號碼預測(2)

今天繼續往下面想以後,發現我以前的想法錯誤了.
本想說,根據歷史資料去統計,以出現次數較少的數字取亂數,又,理論上每個數字出現的次數會趨近一致,所以應該會有較高的機率得到下期中獎的號碼.
回頭想想每期中獎號碼組合機率,應該是以 1 去除以 42 取 6 的所有組合數.
我以排列組合去Google找了很多資料:

要怎麼求組合數呢??我們將樂透的規則套入組合公式:
從 42 個數字中,取 6 個號碼,不論順序,組成一組,不同的組合數為: 排列數/42!
排列組的計算: 42 * (42-1) * (42-2) * (42-3) * (42-4) * (42-5)
42!: 42*41*40*….*2*1
所以寫好以後的程式就是這樣:
using System;
using System.Collections;

public class MyClass
{
    public static double calcP( double totalNumbers, double pickNumbers )
    {
        double possible = 1.0;
        
        for( int i=0; i<pickNumbers; i++ )
            possible = possible * (totalNumbers-i);
            
        return possible;
    }

    public static double calcC( double totalNumbers, double pickNumbers )
    {
        double mShock = 1.0; // m!
        
        for( long i=0; i<pickNumbers; i++ )
            mShock = mShock * (i+1);
        
        double p = calcP( totalNumbers, pickNumbers );
        
        return( p/mShock );
    }

    public static void Main()
    {
        Console.WriteLine( "組合數是: {0}", calcC( 42.0, 6.0 ) );
        
        RL();
    }
    
    #region Helper methods

    private static void RL()
    {
        Console.ReadLine();    
    }
    

    #endregion
}
最後算出來的結果是: 5,245,786
也就是說,如果有 5,245,786 人去買的話,至少會有一人中獎.
不過,還是覺得怪怪的…這數字會不會太小了呢??

樂透下期號碼預測(1)

之前騎車的時候想到的一個 idea,想要來預測下期樂透的號碼.
以亂數取某數字,理論上,當次數越趨近於無限的時候,每個數字出現的機率會趨近於相等.
所以我們寫了這麼一個程式來驗證其正確性:
using System;
using System.Collections;

public class MyClass
{
    public static void Main()
    {
        Random r = new Random();
        int[] statistics = new int[43];
        int i=0;
        int sum=0;
        
        // initialize
        for( i=0; i<statistics.Length; i++ )
            statistics[i]=0;
            
        for( i=0; i<100000; i++ )
        {
            // int index = Convert.ToInt32( 41*r.NextDouble()+1 );
            int index = r.Next(42)+1;
            statistics[ index ] = statistics[ index ] + 1;
        }
        
        for( i=0; i<statistics.Length; i++ )
        {
            Console.WriteLine( "statistics[{0}] = {1}", i, statistics[i] );
            sum+=statistics[i];
        }
        Console.WriteLine( "sum={0}", sum );
            
        RL();
    }
    
    #region Helper methods
    private static void RL()
    {
        Console.ReadLine();    
    }
    #endregion
}
這邊遇到一件很有趣的事情,如果你用 41*r.NextDouble()+1 來取的話
結果會是最前面數字與最後面數字出現的機率會比其他數字要少了約一倍.
所以這樣取會比較好些: r.Next(42)+1
另外我們捨棄 [0] 不用,純使用 [1] ~ [42], 以方便我們的統計.
參考資料:

…待續…

CheckSum

CheckSum 是一個很簡單的檢查方法,把內容拆解成一堆 byte (或word,dword), 如果把這些 bytes 相加起來得到的值一致,表示內容”應該”是沒問題.

using System;
using System.IO;
using System.Collections;

public class CheckSum
{
    private long sum=0;
    
    public CheckSum()
    {
    }

    public void Add( int i )
    {
        sum += i;
    }
    
    public void Add( byte b )
    {
        sum += b;
    }
    
    public long GetCheckSum()
    {
        return sum;
    }
}

public class MyClass
{
    public static void Main()
    {
        string filename;
        FileStream fs=null;
        CheckSum sum = new CheckSum();
        
        //Open the stream and read it back.
        Console.Write( "Please input filename:" );
        filename = Console.ReadLine();
        Console.WriteLine( "Trying to read {0}", filename );
        
        if( File.Exists( filename ) )
            Console.WriteLine( "{0} is existed.", filename );

        try
        {
            fs = File.Open( filename, FileMode.Open, FileAccess.Read );
            
            if( fs.CanRead )
            {
                int value=0;
                
                while( (value = fs.ReadByte()) >= 0)
                {
                    sum.Add( value );
                }
                
                Console.WriteLine( "Checksum = {0,8:x}", sum.GetCheckSum() );
            }
            else
                Console.WriteLine( "Cannot be read" );
        }
        catch( Exception ex )
        {
            Console.WriteLine( ex.Message );
        }
        finally
        {
            fs.Close();
        }
        
        RL();
    }
    
    #region Helper methods
    private static void RL()
    {
        Console.ReadLine();    
    }
    #endregion
}

最大公因數/輾轉相除法

在某論壇看到討論最大公因數的討論串,裡面有提到輾轉相除法.
老實說,當我看到最大公因數,我只想到暴力法.
從 1…n 開始 iterate, 能整除,表示是因數,把這些數字記起來,於是我們得到兩個集合.這兩個集合的交集,表示是共通因數,最大者則為最大公因數.
完全忘記有輾轉相除法這玩意兒,一時興起,port 到 c# 試試看.
using System;
using System.Collections;

public class MyClass
{
    public static int GCD( int a, int b )
    {
        if( a % b == 0 )
            return b;
        return GCD( b, a%b );
    }
    
    public static void Main()
    {
        int num1=1230, num2=460, num3=10;
        
        int result1 = GCD( num1, num2 );
        int result2 = GCD( result1, num3 );
        
        Console.WriteLine( "The GCD of {0} and {1} is {2}", num1, num2, result1 );
        Console.WriteLine( "The GCD of {0} and {1} is {2}", result1, num3, result2 );
        
        RL();
    }
    
    #region Helper methods
    private static void RL()
    {
        Console.ReadLine();    
    }
    #endregion
}

Asp.Net 與 tortoisesvn

早上去看tortoisesvn的時候,發現已經釋出新版,看了一下新版的發行公告,發現新版的tortoisesvn已經解決討厭的 asp.net 問題了.

The “_svn” hack is now officially supported: since some versions of ASP.NET don’t allow directories beginning with dot (e.g., “.svn”, the standard Subversion working copy administrative directory), TortoiseSVN now treats the environment variable SVN_ASP_DOT_NET_HACK specially. If this variable is set (to any value), it will use “_svn” instead of “.svn”. Note that once the environment variable is set, working copies with standard “.svn” directories will stop working, and will need to be re-checked-out to get “_svn” instead.

簡單的說,只要設置環境變數:SVN_ASP_DOT_NET_HACK 就行了.
不知道 subversion 是不是也是一樣的設置方法.

mono 與 SELinux

重灌 server 並啟用 SELinux 以後,發現 asp.net 應用程式無法啟動.
原本不想碰 SELinux 的,不得已,出來混的早晚都要還,只好硬著頭皮去K.
經過研讀文件之後,大致上對 SELinux 有一定的瞭解.
SELinux 本身純粹是作安全性的加強,所以不管是 user, file, directory, socket, process…等等的,都另外有了 security context,作為安全性的第二道防線.
當系統要存取這些資源的時候,首先會使用原有的 unix permission 去作檢查,接著 SELinux 會再依照 security context 作第二道檢查,當檢查沒問題之後,才會允許存取.
SELinux 裡面有所謂的 identity, domain, type, security context, target context 等等物件…
大致上來說, identity 決定身份, domain 決定 process 能幹麼, type 決定 process 以外的物件可以幹麼, security context, target context 則是 identity + domain + type 的組合. policy 則用來定義 security context, target context 可以存取哪些物件. (這些組合,真的很讓人頭暈.)
存取的指令也蠻多的:

  • 要看檔案目錄的 security context, 可以加上 -Z (ls -Z)
  • 要看process的 security context, 也可以用 -Z (ps axZ)
  • 要看自己的security context,可以用 id
  • 要改security context, 可以用 chcon
  • 要 reset security context, 可以用 restorecon

整個研讀完之後,發現應該是 policy 問題.
今天下午用Google去找到 v14, i08: Tuning Your SELinux Policy with Audit2allow” href=”http://www.samag.com/documents/s=9820/sam0508a/0508a.htm”>這篇文章,發現有這麼個工具 – audit2allow,他是在 policycoreutils 套件裡面的指令,可以根據 warning message 產生 policy,省掉不少編寫的麻煩.
為了要能重新編譯 policy, 你需要安裝 selinux-policy-targeted-sources 這個套件

yum install selinux-policy-targeted-sources

再使用 audit2allow 這個指令,從 dmesg 裡面分析 warning, 並將產生以後的 policy 寫入到 mono.policy 檔案中.

audit2allow -d -o mono.policy

接著把 mono.policy 更名為 local.te, 放到 /etc/selinux/targeted/src/policy/domains/misc/ .
放完之後,切換到 /etc/selinux/targeted/src/policy
強制 selinux 重新編譯 policy

make load

最後重新啟動我的 Apache server,就大功告成了.
參考資料:

ThreadAbortException

原來呼叫 Response.End() 就會丟出 ThreadAbortException.
害我以為是我程序出現錯誤了呢…
Google 幫忙一下,原來也有人碰到同樣情況:
Impersonation Failure : ASP.NET – ThreadAbortException
其實還不只是 Response.End(), Server.Transfer() 與 Response.Redirect() 也有機會發生此狀況,因為他們內部也呼叫了 Response.End().
比較正確的作法應該還是先呼叫

Response.Flush();
Response.Close();

會比較好些.
這是那篇文章所提供的參考資料: