2013-04-27 5 views
1

Мне нужно извлечь чисел, разделенных запятыми из строк, как это (с произвольным кол чисел и пробелов):Регулярные выражения

Expression type:   Answer: 
(1, 2,3)     1,2,3 
(1,3,4,5,77)    1,3,4,5,77 
(b(2,46,8,4,5, 52) y) 2,46,8,4,5,52 
(a (3, 8,2, 1, 2, 9) x)  3,8,2,1,2,9 

Благодаря

+0

a) Какие части этого являются переменными? б) Что вы пробовали? –

+0

Эта переменная имеет такие числа: (число, число, ..., число) в скобках могут быть с пробелами. Я использовал простой метод разделения, но это не изящно и подвержено ошибкам. – Nmktronas

ответ

1

является поиск exaclty строка вы всегда будете иметь, как вы его разместили?

(число1, число2, numer3) текст ...

Edit: Вы представили новые примеры этого должны обращаться с ними:

string input = "(b(2,46,8,4,5, 52) y)"; 
    input = input.Remove(" ",""); 
    var result = Regex.Matches(input, @"\(([0-9]+,)+[0-9]+\)"); 
    Console.WriteLine(result[0]); 
+0

Это правда, но его вопрос не показывает других случаев. Im не уверен, что ему нужно – WhileTrueSleep

+1

Этот код также будет соответствовать номерам, разделенным пробелами, например. '(1 2,3)', но не будет соответствовать одиночным числам, например. '(1)'. –

3

Попробуйте эту модель:

\((?:\s*\d+\s*,?)+\) 

Например:

var results = Regex.Matches(input, @"\((?:\s*\d+\s*,?)+\)"); 
Console.WriteLine(results[0].Value); // (1,2,3) 

Если вы хотите, чтобы преобразовать это в список целых чисел вы можете сделать это довольно легко с Linq:

var results = Regex.Matches(input, @"\((?:\s*(\d+)\s*,?)+\)") 
        .Cast<Match>() 
        .SelectMany(m => m.Groups.Cast<Group>()).Skip(1) 
        .SelectMany(g => g.Captures.Cast<Capture>()) 
        .Select(c => Convert.ToInt32(c.Value)); 

Или в синтаксисе запроса:

var results = 
    from m in Regex.Matches(input, @"\((?:\s*(\d+)\s*,?)+\)").Cast<Match>() 
    from g in m.Groups.Cast<Group>().Skip(1) 
    from c in g.Captures.Cast<Capture>() 
    select Convert.ToInt32(c.Value); 
+0

Это будет фиксировать отдельные числа (с их запятыми запятыми), а не все '(1,2,3)'. –

+0

@ m.buettner Конечно. 'results [0] .Value' будет' (1,2,3) ' –

+0

О, правильно. По-видимому, это еще слишком рано ... Вы могли бы сделать эту группу не захватывающей, хотя и (?: \ D +,?) '... как хорошая практика, я думаю. –

1

Увидев там также могут быть пробелы, здесь есть предположение, что unrolls the loop (который является немного более эффективным для больших входов):

@"[(]\d+(?:,\d+)*[)]" 

Вы можете, конечно, избежать скобок с обратными косыми чертами, тоже. Я просто хотел показать альтернативу, которую я лично считаю более читаемой.

Если вы в конечном итоге хотите получить номера, вместо того, разделив результат регулярных выражений, вы можете захватить их сразу:

@"[(](?<numbers>\d+)(?:,(?<numbers>\d+))*[)]" 

Теперь группа numbers будет список всех чисел (как строки).

Я полностью снова забыл о пространствах, поэтому здесь с пробелами (которые не являются частью захватов):

@"[(]\s*(?<numbers>\d+)\s*(?:,\s*(?<numbers>\d+)\s*)*[)]" 
+1

Хотя я согласен, что это более читаемо, это не учитывает пробелы. Также я не знал, что вы можете повторно использовать имена групп. –

+0

@ p.s.w.g Из-за того, что он не хочет иметь пробелы в своем результате, я удалял их перед использованием регулярного выражения. – WhileTrueSleep

+0

@WhileTrueSleep +1, потому что это полностью отвечает на проблему OP. Но было бы более эффективно вырезать их после матча, хотя, поскольку размер строки будет меньше? –

1

я бы, вероятно, использовать регулярное выражение как это:

\((\d+(?:\s*,\s*\d+)*)\) 

с PowerShell кода:

$str = @(
    "(1, 2,3)" 
    , "(1,3,4,5,77)" 
    , "(b(2,46,8,4,5, 52)" 
    , "(a (3, 8,2, 1, 2, 9) x)" 
    , "(1)" 
    , "(1 2, 3)" # no match (no comma between 1st and 2nd number) 
    , "(1,2,3)" # no match (leading whitespace before 1st number) 
    , "(1,2,3)" # no match (trailing whitespace after last number) 
    , "(1,2,)"  # no match (trailing comma) 
) 
$re = '\((\d+(?:\s*,\s*\d+)*)\)' 

$str | ? { $_ -match $re } | % { $matches[1] -replace '\s+', "" } 

регулярное выражение будет соответствовать (суб) строку, начинается с открывающей круглой скобки, за которой следует разделенная запятыми последовательность чисел (которая может содержать любое количество пробелов до запятой или после нее) и заканчивается закрывающей скобкой. Затем пробел удаляется инструкцией -replace.

Если вы не хотите, чтобы соответствовать одиночные номера ("(1)"), изменить регулярное выражение следующим образом:

\((\d+(?:\s*,\s*\d+)+)\) 

Если вы хотите разрешить пробелы после открытия или перед закрывающей скобкой, изменить регулярное выражают следующее:

\(\s*(\d+(?:\s*,\s*\d+)*)\s*\) 
Смежные вопросы