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