2013-11-14 4 views
2

Почему регулярное выражение работает неправильно?Regex ", \ s (. *?), \ s"

string findarg2 = ",\\s(.*?),\\s"; 

foreach (Match getarg2 in Regex.Matches(tmptwopart, findarg2)) 
if (getarg2.Success) 
{ 
    for (int m = 1; m < getarg2.Groups.Count; m++) 
    { 
     int n; 
     bool needpointer = false; 
     for (n = getarg2.Groups[m].Value.Length - 1; n > -1; n--) 
     { 
      if (getarg2.Groups[m].Value[n] == ' ') 
       break; 
      else if (getarg2.Groups[m].Value[n] == '*') 
      { 
       needpointer = true; 
       break; 
      } 
     } 
     n++; 

     string part1 = getarg2.Groups[m].Value.Remove(n); 
     string part2 = getarg2.Groups[m].Value.Remove(0, n); 
     Console.WriteLine(getarg2.Groups[m] + " =->" +part1+ " AND " + part2); 
     Console.ReadKey(); 
     if (needpointer) 
     { 
      createarglist.Append("<< *(" + part1 + ")" + part2); 
     } 
     else 
     { 
      createarglist.Append("<< " + part2); 
     } 
     createarglistclear.Append(part2+","); 
    } } 

Пример введите строку:

(DWORD code, bool check, float *x1, float *y1, float *x2, float *y2) 

Выход:

<< check<< *(float *)y1 

Ожидаемое:

<< check<< *(float *)x1<< *(float *)y1<< *(float *)x2 
+2

В чем проблема? – Matthew

+3

Каков ваш ожидаемый результат? –

+0

Need << check << * (float *) x1 << * (float *) y1 << * (float *) x2 –

ответ

3

Причина, по которой выражение не работает, заключается в том, что оно «потребляет» запятую: часть, которая соответствует check, также ест запятую после нее, предотвращая сопоставление float *x1; то же самое происходит с выражением, которое соответствует float *y1.

Изменение выражения для использования lookaheads и lookbehind должно работать. Однако этого может быть недостаточно, потому что в первом матче перед ним не будет запятой, а у последней не будет запятой после нее.

Лучшее выражение для использования в этом случае должно быть таким:

(?<=[(,])\\s*([^,)]*)\\s*(?=[,)]) 

Вот полный пример кода:

foreach (Match m in Regex.Matches(
    "(DWORD code, bool check, float *x1, float *y1, float *x2, float *y2)" 
, "(?<=[(,])\\s*([^,)]*)\\s*(?=[,)])") 
) { 
    for (var i = 1 ; i != m.Groups.Count ; i++) { 
     Console.WriteLine("'{0}'", m.Groups[i]); 
    } 
} 

Вот demo on ideone производить шесть групп, как ожидалось:

'DWORD code' 
'bool check' 
'float *x1' 
'float *y1' 
'float *x2' 
'float *y2' 
+0

+1 - Хороший момент о первом и последнем матчах. Для @FakEFake в этом случае используйте оператор '|' в рамках утверждений, чтобы обеспечить более гибкие случаи. (C# допускает переменные ширины lookbehinds, поэтому он будет работать.) –

4

Это потому, что вы потребляя завершающие запятые, как вы идете. То есть вы уже сопоставили конечную запятую, поэтому она не соответствует ведущей запятой для следующего объекта, который вы пытаетесь сопоставить. Использование нулевой ширины утверждения вместо того, чтобы:

string findarg2 = "(?<=,\\s)(.*?)(?=,\\s)"; 

Они известны как «и» просмотра назад «упреждающего поиска» утверждений, соответственно.

+0

Спасибо! Оно работает. –

0

Это можно сделать одним выстрелом:

string input = "(DWORD code, bool check, float *x1, float *y1, float *x2, float *y2)"; 
string pattern = @"(?:\([^,]*,\s*[^\s,]*\s+([^,]+)|\G),\s+(\S+)\s*(\*)?((?>[^*,)]+))(?>(?=,[^,]+,)|.*)"; 
string replacement = "$1<< *($2$3)$4"; 
Regex rgx = new Regex(pattern); 
string result = "<<" + rgx.Replace(input, replacement); 
+0

Нет, это абсолютно неправильно. –

+0

@FakEFake: что не так? –

+0

@FakEFake: Я забыл '@' перед строкой шаблона. Попробуй это сейчас. –

Смежные вопросы