2015-01-07 6 views
1

Мне нужно разобрать список номеров и номеров номеров, разделенных запятыми. Строки вводятся в пользовательском интерфейсе пользователем и будет выглядеть как один из них (шесть различных образцов входов):.NET Regex выражение для разбора списка чисел и диапазонов чисел

1-3, 5, 7-10 
1 
21.1 
1.2-3,5.1,7-10.1 
1-3, 5.1, 7-10, 21 
1.1-3.1,5.1,7.1-10.1 

Моя конечная цель иметь коллекцию числа и числа диапазонов, которые можно обработать позже вниз по течению , Например, после разбора первого образца строки выше моего конечного результата будет сбор, содержащий 3 элемента: 1-3, 5 и 7-10.

Использование C# и .NET Regex эта модель хорошо заполняет коллекцию соответствий с только пункты мне нужно (Обратите внимание на использование не-захвата групп):

(\d+(?:\.\d+)?-\d+(?:\.\d+)?)|(\d+(?:\.\d+)?) 

У меня есть два вопроса, хотя:

  1. Нужно ли мне все это в моем шаблоне или существует ли более короткий шаблон?

  2. Есть ли что-то, что я могу добавить к шаблону, чтобы возвращать 0 совпадений, когда есть недопустимые символы, содержащиеся в строке? Например, если я включаю альфа-символ в строку в любом месте, я бы не хотел, чтобы совпадения не встречались. Сейчас я делаю это с двумя проходами, один для проверки того, что строка имеет только допустимые символы [\ d, .-] и другой проход, чтобы получить совпадения, предполагающие, что они подтверждены в первом проходе.

Заранее благодарим за идеи.

Update:

Вот решение, которое я в конечном итоге происходит с (см @ Xiaoy312 ответ):

public static IEnumerable<DataRange> ParseInput(string input) 
{ 
    if (!Regex.IsMatch(input.Replace(" ", string.Empty), @"^[\d\.,\-]+$")) 
     return Enumerable.Empty<DataRange>(); 

    return Regex.Matches(input.Replace(" ", string.Empty), 
     @"(?<A>\d+(?:\.\d+)?)(?:-(?<B>\d+(?:\.\d+)?))?").Cast<Match>() 
     .Select(m => new DataRange 
     { 
      A = double.Parse(m.Groups["A"].Value, 
       System.Globalization.CultureInfo.InvariantCulture), 
      B = m.Groups["B"].Success ? double.Parse(m.Groups["B"].Value, 
       System.Globalization.CultureInfo.InvariantCulture) : (double?)null 
     }); 

} 

public class DataRange 
{ 
    public double A; 
    public double? B; 
} 

Вот пример использования: выход

static void Main(string[] args) 
{ 
    Console.WriteLine("A\tB"); 
    var items = ParseInput("1"); 
    Array.ForEach(items.ToArray(), i => Console.WriteLine("{0}\t{1}", i.A, i.B)); 
    items = ParseInput("21.1"); 
    Array.ForEach(items.ToArray(), i => Console.WriteLine("{0}\t{1}", i.A, i.B)); 
    items = ParseInput("1-3,5,7-10"); 
    Array.ForEach(items.ToArray(), i => Console.WriteLine("{0}\t{1}", i.A, i.B)); 
    items = ParseInput("1.2-3,5.1,7-10.1"); 
    Array.ForEach(items.ToArray(), i => Console.WriteLine("{0}\t{1}", i.A, i.B)); 
    items = ParseInput("1-3, 5.1, 7-10,21"); 
    Array.ForEach(items.ToArray(), i => Console.WriteLine("{0}\t{1}", i.A, i.B)); 
    items = ParseInput("1.1-3.1,5.1,7.1-10.1"); 
    Array.ForEach(items.ToArray(), i => Console.WriteLine("{0}\t{1}", i.A, i.B)); 
    items = ParseInput("1.1-3.1,5.1,7.1-10.1a"); 
    Array.ForEach(items.ToArray(), i => Console.WriteLine("{0}\t{1}", i.A, i.B)); 
} 

Пример:

A  B 
1 
21.1 
1  3 
5 
7  10 
1.2  3 
5.1 
7  10.1 
1  3 
5.1 
7  10 
21 
1.1  3.1 
5.1 
7.1  10.1 
+3

Что вы делаете, что не может быть достигнуто с двумя или три ['String.Split()'] (http://msdn.microsoft.com/en-us /library/system.string.split%28v=vs.110%29.aspx)? – valverij

+0

Что-то по строкам '\ d * (\. \ D *)? (- (\ d * (\. \ D *)?))?' Должно быть допустимым упрощением. Чтобы проверить все, что вам нужно было бы связать с этим регулярным выражением в группе захвата внутри другой, содержащей запятые и необязательные пробелы. –

+1

Я бы сказал: '\ d + (?: \. \ D +)? (?: - \ d + (?: \. \ D +)?)?'. Используйте группу захвата '0' (полное совпадение). –

ответ

1

Первый r ushed попытка на него:

public IEnumerable<object> ParseInput(string input) 
{ 
    return Regex.Matches(input.Replace(" ", string.Empty), @"(?<A>\d+(\.\d+)?)(-(?<B>\d+(\.\d+)?))?").Cast<Match>() 
     .Select(m => new 
     { 
      A = m.Groups["A"].Value, 
      B = m.Groups["B"].Value 
     }); 
} 

Исправлено:

public IEnumerable<DataRange> ParseInput(string input) 
{ 
    if (!Regex.IsMatch(input.Replace(Environment.NewLine, string.Empty), @"^[\d\.,\- ]+$")) 
     return Enumerable.Empty<object>(); 

    return input 
     .Replace(" ", string.Empty) 
     .Split(new[] { Environment.NewLine, "," }, StringSplitOptions.RemoveEmptyEntries) 
     .Select(x => Regex.Match(x, @"(?<A>\d+(\.\d+)?)(-(?<B>\d+(\.\d+)?))?")) 
     .Select(m => new DataRange 
     { 
      A = double.Parse(m.Groups["A"].Value, System.Globalization.CultureInfo.InvariantCulture), 
      B = m.Groups["B"].Success ? double.Parse(m.Groups["B"].Value, System.Globalization.CultureInfo.InvariantCulture) : (double?)null 
     }); 
} 

public class DataRange 
{ 
    public double A; 
    public double? B; 
} 

Вход:

const string SampleInput = 
    @"1-3, 5, 7-10, 
1 
21.1 
1.2-3,5.1,7-10.1 
1-3, 5.1, 7-10, 21 
1.1-3.1,5.1,7.1-10.1"; 

Выход:

A B 
1 3 
5 null 
7 10 
1 null 
21,1 null 
1,2 3 
5,1 null 
7 10,1 
1 3 
5,1 null 
7 10 
21 null 
1,1 3,1 
5,1 null 
7,1 10,1 
+0

Спасибо !!! Твоей «Первой бросившейся попытки» было много, меня это заставило. Затем я увидел ваш «Исправленный» пример, который был выше и выше ... спасибо за это. FYI, нет необходимости разбирать символы новой строки, так как каждая строка в моем исходном наборе образцов была входной, т. Е. Шесть отдельных входов во всех, каждый анализировался независимо друг от друга. – KyleLib

+0

О, я думал, что это один вход. Ха-ха. – Xiaoy312

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