2009-09-02 32 views
1

我正在開發一個小型應用程序,需要用它們的值替換字符串中的.NET樣式「變量」。一個例子如下:使用正則表達式.NET樣式的可變擴展

替換:

「{d}/{MM}/{YYYY}」

隨着: 「31/12/2009」

我決定使用正則表達式來查找「{var}」的出現,但我不太確定如何正確地使用它。

回答

4

如果你要使用正則表達式,和你有一個已知的模式,它沒有得到比使用匹配評估方法,而不是調用更簡單的更換了一堆時間:

void Main() // run this in LinqPad 
{ 
    string text = "I was here on {D}/{MMM}/{YYYY}."; 
    string result = Regex.Replace(text, "{[a-zA-Z]+}", ReplaceMatched); 

    Console.WriteLine(result); 
} 

private string ReplaceMatched(Match match) 
{ 
    if(match.Success) 
    { 
     switch(match.Value) 
     { 
      case "{D}": 
       return DateTime.Now.Day.ToString(); 
      case "{YYYY}": 
       return DateTime.Now.Year.ToString(); 
      default: 
       break; 
     } 
    } 
    // note, early return for matched items. 

    Console.WriteLine("Warning: Unrecognized token: '" + match.Value + "'"); 
    return match.Value; 
} 

給結果

 
Warning: Unrecognized token: '{MMM}' 
I was here on 2/{MMM}/2009. 

它沒有完全實施明顯。

退房LinqPad和正則表達式的工具,像Expresso

+0

+1 - 我真正喜歡.NET regexps的兩件事是這樣的,並且能夠解析任意嵌套的構造。 – 2009-09-02 03:07:36

0

下面是一些代碼,我在一個日誌實用程序,它幾乎正是你想要的使用,雖然格式稍有不同:

Regex rgx = new Regex("{([Dd]:([^{]+))}"); 

    private string GenerateTrueFilename() 
    { 
     // Figure out the new file name 
     string lfn = LogFileName; 
     while (rgx.IsMatch(lfn)) 
     { 
      Match m = rgx.Matches(lfn)[0]; 
      string tm = m.Groups[1].Value; 
      if (tm.StartsWith("D:")) 
      { 
       string sm = m.Groups[2].Value; 
       string dts = DateTime.Now.ToString(sm); 
       lfn = lfn.Replace(m.Groups[0].Value, dts); 
      } 
     } 

     return lfn; 
    } 

的RGX定義格式,目前實際上只有一種格式:

d:{datestring}

LOGFILENAME是在代碼別處定義的變量,但是有一個默認:

LogFileName = "LogFile.{D:yyyy-MM-dd}.log" 

所以希望您能從中看到如何根據需要繼續處理其他變量。

1

正則表達式真的很強大,但也需要很多開銷。它可能會更簡單使用類似inputString.Replace("{var}", value)代替:

void Foo() 
{ 
    string s = "{D}/{MM}/{YYYY}"; 
    s = ReplaceTokenInString(s, "{D}", "31"); 
    s = ReplaceTokenInString(s, "{MM}", "12"); 
    s = ReplaceTokenInString(s, "{YYYY}", "2009"); 
} 

string ReplaceTokenInString(string input, string token, string replacement) 
{ 
    input.Replace(token, replacement); 
} 
+0

除了創建這2箇中間字符串....沒有什麼大不了的,只有3個替換字符串,但它不是很聰明。使用StringBuilder及其'方法sb.Replace可能會更好,當你認爲'程序'的重點是要取代東西。另外,爲什麼將事情與1行方法ReplaceTokenInString進行混淆,它確實實現了s.Replace的功能? – 2009-09-02 01:53:44

+0

@Robert Paulson:使用StringBuilder進行替換不一定比創建新字符串更有效 - 如果令牌及其替換長度不同,則不會更有效。您的MatchEvaluator解決方案通過一次性完成所有事情,輕鬆擊敗兩種方法。 – 2009-09-02 02:53:33

+0

@Alan M,真的,這就是爲什麼我說'可能',因爲我從來沒有描述它,但至少希望它更好。 – 2009-09-02 04:33:21

0

如果你正在做的具體日期,你應該考慮使用format string。很顯然,如果你做的不僅僅是這些,這對你無能爲力。

0

我用正則表達式做了它,並使用一個StringBuilder。我在源字符串中找到匹配項,並追加字符串和評估匹配項的塊。

StringBuilder text = new StringBuilder(snippet.Length * 2); 
Regex pattern = new Regex("\\{[A-Za-z]+\\}"); 
MatchCollection matches = pattern.Matches(snippet); 
if (matches.Count == 0) return snippet; 

int from = 0; 
foreach (Match match in matches) 
{ 
    text.Append(snippet.Substring(from, match.Index - from)); 
    string variable = snippet.Substring(match.Index + 1, match.Length - 2); 
    text.Append(EvaluateVariable(variable)); 
    from = match.Index + match.Length; 
} 
text.Append(snippet.Substring(from)); 
return text.ToString(); 
+0

太棒了!您剛剛重新創建了Regex.Replace方法。你真的應該再看看羅伯特·保爾森的回答。 – 2009-09-02 05:51:51

+0

是的,我甚至沒有注意到答案。我來自本地C++,去圖哈哈 – 2009-09-02 23:01:35