2012-01-10 41 views
2

重建特定字符串:節 - 從這個屠宰一個

53_2_b 
50 
48_1_b_i 
50A_3_b 
48_1_b_iv 

日期:

53(2)(b) 
50 
48(1)(b)(i) 
50A(3)(b) 
48(1)(b)(iv) 

(他們是我想從立法已轉化爲NCNames部分引用。到unconvert他們。)

有一些令人尷尬的少量的代碼要做到這一點,這會教我很多?

這是我目前有:

readonly Func<char, bool> _isNotUnderscore = c => c != '_'; 

string ConvertFragmentToSecRef(string frag) 
{   
    var p0 = new Regex(@"^[0-9]+[A-Z]*"); 
    var p1 = new Regex(@"[0-9]+"); 
    var p2 = new Regex(@"[\w]+"); 
    var p3 = new Regex(@"(i|v|x)+"); 

    var regexes = new[] {p0, p1, p2, p3}; 

    var sb = new StringBuilder(); 

    Recurse(frag,0,ref regexes,ref sb); 

    return sb.ToString(); 
} 

void Recurse(string left,int level, ref Regex[] regexes,ref StringBuilder sb) 
{ 
    if (level < 4) 
    { 
     var head = String.Concat(left.TakeWhile(_isNotUnderscore)); 
     var tail = String.Concat(left.Skip(head.Count())).TrimStart('_'); 
     if (regexes[level].IsMatch(head)) 
     { 
      sb.Append(level == 0 ? head : "(" + head + ")"); 
      Recurse(tail, level + 1, ref regexes, ref sb); 
     } 
    } 
} 

回答

5

你不需要遞歸對於這一點,只是lookahead assertions

resultString = Regex.Replace(subjectString, 
    @"_   # match _ 
    ([^_\r\n]*) # match whatever follows except _ or newlines 
    (?=[_\r]|$) # assert that a _ or end-of-line follows", 
    "($1)", RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace); 

這個工作對你多輸入字符串。當然,如果你有一個單獨的字符串的每一行,很容易:

resultString = Regex.Replace(subjectString,  
    @"_      # match _ 
    ([^_]*)  # match whatever follows except _ 
    (?=_|$)  # assert that a _ or end-of-string follows",  
    "($1)", RegexOptions.IgnorePatternWhitespace); 
+0

整潔,但它不會產生期望的結果(例如,第三行是這樣的:'48(1)(B) _i'而不是'48(1)(b)(i)')。你可以微調這個嗎? – GolfWolf 2012-01-10 10:30:19

+0

啊,這可能與無論什麼原因在'\ r'和'\ n'之間匹配'$'的.NET問題有關。試用新版本 - 現在可以使用嗎? – 2012-01-10 10:43:21

+0

是的,現在可以使用。非常有趣的解決方案,直到現在我才知道正則表達式中的lookahead/lookbehind斷言。 +1 – GolfWolf 2012-01-10 10:55:05

相關問題