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

Текстовая строка, которую я хочу проверить, состоит из того, что я называю «сегментами». Отдельный сегмент может выглядеть так:

 [A-Z,S,3]

До сих пор мне удалось построить этот шаблон регулярного выражения

(?:\[(?<segment>[^,\]\[}' ]+?,[S|D],\d{1})\])+?

он работает, но будет возвращать совпадения, даже если вся текстовая строка содержит недопустимый текст. Я предполагаю, что мне нужно использовать ^ и $ где-то в моем шаблоне, но я не могу понять, как!?

Я хотел бы, чтобы мой шаблон дал следующие результаты:

  • [A-Z,S,3][A-Za-z0-9åäöÅÄÖ,D,4] ОК(два сегмента)
  • [A-Z,S,3]aaaa[A-Za-z0-9åäöÅÄÖ,D,4] Нет совпадений
  • crap[A-Z,S,3][A-Za-z0-9åäöÅÄÖ,D,4] Нет совпадений
  • [A-Z,S,3][] Нет совпадений
  • [A-Z,S,3][klm,D,4][0-9,S,1] ОК(три сегмента)

person David    schedule 01.01.2010    source источник
comment
С# (последняя версия .Net 3.5). Я также хотел бы извлечь сегменты, если я получу успешное совпадение (если возможно). Возможно, мне нужно иметь второй шаблон, чтобы сделать это?   -  person David    schedule 01.01.2010


Ответы (2)


Используйте ^ для привязки начала и $ для привязки конца. Например: ^(abc)*$, это соответствует нулю или более повторений группы (в данном примере "abc") и должно начинаться в начале входной строки и заканчиваться в ее конце.

^(?:[(?[^,][}' ]+?,[S|D],\d{1})])+$использование нежадного +? не имеет значения, так как вам все равно нужно, чтобы оно совпадало до конца. Однако у вашего регулярного выражения есть несколько проблем.

^(?:\[[^,]+,[SD],\d\])+$похоже на то, что вы хотите.

  • Я не мог расшифровать, что вы имели в виду под первой частью, поэтому мое регулярное выражение более общее, чем требуется, [^,]+, будет соответствовать любой последовательности незапятых, за которыми следует запятая, и на самом деле вам, вероятно, следует добавить ] к этому инвертированному классу символов.
  • [S|D] — это класс символов из трех символов, поскольку | здесь не означает чередование (хотя (S|D) означает то же, что и [SD]).
  • {1} — значение по умолчанию для любого атома, указывать его не нужно.

Псевдокод (запустите его по адресу codepad.org):

import re
def find_segments(input_string):
  results = []
  regex = re.compile(r"\[([^],]+),([SD]),(\d)\]")
  start = 0
  while True:
    m = regex.match(input_string, start)
    if not m: # no match
      return None # whole string didn't match, do another action as appropriate
    results.append(m.group(1, 2, 3))
    start = m.end(0)
    if start == len(input_string):
      break
  return results

print find_segments("[A-Z,S,3][klm,D,4][0-9,S,1]")
# output:
#[('A-Z', 'S', '3'), ('klm', 'D', '4'), ('0-9', 'S', '1')]

Большая разница здесь в том, что выражение соответствует только полной части [...], но оно применяется последовательно, поэтому они должны начинаться снова там, где заканчивается последняя (или заканчиваться в конце строки).

person Community    schedule 01.01.2010
comment
Спасибо! Отличный ответ на мой вопрос. Дело в том, что я также хотел бы извлечь сегменты. Либо в коллекции матчей, либо в группах. Если вы посмотрите на мой исходный шаблон, вы увидите, что сначала у меня есть группа без захвата, а затем группа захвата, извлекающая сегмент. Можно ли включить это в свой шаблон? - person David; 01.01.2010
comment
Да, точно так же, добавьте группу захвата вокруг того, что вас интересует. Однако вам, вероятно, потребуется вызвать библиотеку регулярных выражений с другой функцией, чтобы захватить все из них, а не только первый или последний , так как группа захвата вместо этого является повторением. Я обновлю пример. - person ; 01.01.2010
comment
+1: это хороший способ решить эту проблему на Python. Это избавляет от двух почти идентичных регулярных выражений и снижения производительности при двойном совпадении одной и той же строки. Но есть ли у Regex .NET возможность сказать, где должно начинаться совпадение, как в Python, или это потребует копирования строк, что сведет на нет преимущество в производительности? - person Mark Byers; 01.01.2010
comment
тогда внутри* повторение. (Вы входите на территорию, специфичную для движка регулярных выражений.) - person ; 01.01.2010
comment
Марк: бьет меня - если бы этот вопрос был помечен как специфичный для C # с самого начала, я бы, вероятно, воздержался (но вы, похоже, все равно хорошо рассмотрели эту часть). Время от времени важно выбрать, где останавливается другое регулярное выражение — вы можете применить совершенно другое выражение или попробовать разные в этот момент. - person ; 01.01.2010
comment
Спасибо всем вам! Вы действительно приложили много усилий, чтобы помочь мне! - person David; 01.01.2010

Вы хотите что-то вроде этого:

/^(\[[^],]+,[SD],\d\])+$/

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

using System;
using System.Text.RegularExpressions;

class Program
{
    static void Main(string[] args)
    {
        string[] tests = {
            "[A-Z,S,3][A-Za-z0-9,D,4]",
            "[A-Z,S,3]aaaa[A-Za-z0-9,D,4]",
            "crap[A-Z,S,3][A-Za-z0-9,D,4]",
            "[A-Z,S,3][]",
            "[A-Z,S,3][klm,D,4][0-9,S,1]"
        };

        string segmentRegex = @"\[([^],]+,[SD],\d)\]";
        string lineRegex = "^(" + segmentRegex + ")+$";

        foreach (string test in tests)
        {
            bool isMatch = Regex.Match(test, lineRegex).Success;
            if (isMatch)
            {
                Console.WriteLine("Successful match: " + test);
                foreach (Match match in Regex.Matches(test, segmentRegex))
                {
                    Console.WriteLine(match.Groups[1]);
                }
            }
        }
    }
}

Выход:

Successful match: [A-Z,S,3][A-Za-z0-9,D,4]
A-Z,S,3
A-Za-z0-9,D,4
Successful match: [A-Z,S,3][klm,D,4][0-9,S,1]
A-Z,S,3
klm,D,4
0-9,S,1
person Mark Byers    schedule 01.01.2010