Вероятно, простое регулярное выражение - PullRequest
0 голосов
/ 08 сентября 2010

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

 {ValidFunctionName}({parameter}:"{value}")

 {ValidFunctionName}({parameter}:"{value}",
                     {parameter}:"{value}")

 {ValidFunctionName}()

Где {x} - это то, что я хочу сопоставить, {параметр} может быть любым $% "$, например, и {значение} должно быть заключено в кавычки.

ThisIsValid_01(a:"40")

будет" ThisIsValid_01 "," a "," 40 "

ThisIsValid_01(a:"40", b:"ZOO")

будет "ThisIsValid_01", "a", "40", "b", "ZOO"

01_ThisIsntValid(a:"40")

не вернет ничего

ThisIsntValid_02(a:40)

не вернетсячто-нибудь, поскольку 40 не заключено в кавычки.

ThisIsValid_02()

вернет "ThisIsValid_02"

Для правильного имени функции, с которым я столкнулся: "[A-Za-z _] [A-Za-z_0-9] * "Но я не могу на всю жизнь понять, как сопоставить остальные. Я играл на http://regexpal.com/, чтобы попытаться получить действительные совпадения при любых условиях,но безрезультатно: (

Было бы неплохо, если бы вы тоже любезно объяснили регулярное выражение, поэтому я могу выучить:)

Ответы [ 6 ]

2 голосов
/ 08 сентября 2010

РЕДАКТИРОВАТЬ: Это будет работать, использует 2 регулярных выражений. Первый получает имя функции и все внутри нее, второй извлекает каждую пару параметров и значений из того, что находится внутри скобок функции. Вы не можете сделать это с помощью одного регулярного выражения. Добавьте немного [ \t\n\r]* для пробела.

Regex r = new Regex(@"(?<function>\w[\w\d]*?)\((?<inner>.*?)\)");
Regex inner = new Regex(@",?(?<param>.+?):""(?<value>[^""]*?)""");
string input = "_test0(a:\"lolololol\",b:\"2\") _test1(ghgasghe:\"asjkdgh\")";

List<List<string>> matches = new List<List<string>>();

MatchCollection mc = r.Matches(input);
foreach (Match match in mc)
{
    var l = new List<string>();
    l.Add(match.Groups["function"].Value);
    foreach (Match m in inner.Matches(match.Groups["inner"].Value))
    {
         l.Add(m.Groups["param"].Value);
         l.Add(m.Groups["value"].Value);
    }
    matches.Add(l);
}

(Старый) Решение

(?<function>\w[\w\d]*?)\((?<param>.+?):"(?<value>[^"]*?)"\)

(Старый) Пояснение

Давайте удалим групповые снимки, чтобы их было легче понять: \w[\w\d]*?\(.+?:"[^"]?"\)

\w - это слово класс, оно сокращенно от [a-zA-Z_]
\d - это класс цифр, оно сокращенно от [0-9]

  1. \w[\w\d]*? Обеспечивает наличие допустимого символа слова для начала функции, а затем сопоставляет ноль или более других слов или цифр.

  2. \(.+? Соответствует левой скобке, затем одному или нескольким любым символам (для параметра)

  3. :"[^"]*?"\) Соответствует двоеточию, открывающей кавычке, затем нулю или более любого символа, кроме кавычек (для значения), затем закрывающей кавычки и правой скобки.

Скобки (или парены, как их называют некоторые люди), когда избежали с обратными слешами, потому что в противном случае они захватывают группы.

(?<name> ) захватывает некоторый текст.

? после каждого оператора * и + делает их нежадными , что означает, что они будут соответствовать наименьшему, а не большому количеству текста.

(Старый) Использование

Regex r = new Regex(@"(?<function>\w[\w\d]*?)\((?<param>.+?):""(?<value>[^""]*?)""");
string input = "_test0(aa%£$!:\"lolololol\") _test1(ghgasghe:\"asjkdgh\")";

List<string[]> matches = new List<string[]>();

if(r.IsMatch(input))
{
    MatchCollection mc = r.Matches(input);
    foreach (Match match in mc)
    matches.Add(new[] { match.Groups["function"].Value, match.Groups["param"].Value, match.Groups["value"].Value });
}

РЕДАКТИРОВАТЬ: Теперь вы добавили неопределенное количество нескольких параметров, я бы рекомендовал создать свой собственный анализатор, а не использовать регулярные выражения. Приведенный выше пример работает только с одним параметром и без пробелов. Это будет соответствовать нескольким параметрам со строгим пробелом, но не вернет параметры и значения:

\w[\w\d]*?\(.+?:"[^"]*?"(,.+?:"[^"]*?")*\)

Просто для удовольствия, как выше, но с пробелами:

\w[\w\d]*?[ \t\r\n]*\([ \t\r\n]*.+?[ \t\r\n]*:[ \t\r\n]*"[^"]*?"([ \t\r\n]*,[ \t\r\n]*.+?[ \t\r\n]*:[ \t\r\n]*"[^"]*?")*[ \t\r\n]*\)

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

1 голос
/ 08 сентября 2010

Кто-то уже дал ответ, который дает вам простой список строк, но в интересах строгой типизации и правильной структуры классов, я собираюсь предоставить решение, которое правильно инкапсулирует данные.

Сначала объявляем два класса:

public class ParamValue         // For a parameter and its value
{
    public string Parameter;
    public string Value;
}
public class FunctionInfo       // For a whole function with all its parameters
{
    public string FunctionName;
    public List<ParamValue> Values;
}

Затем выполните сопоставление и заполните список FunctionInfo s:

(Кстати, я сделал несколько небольших исправлений в регулярных выражениях ... теперь он будет корректно соответствовать идентификаторам и не будет включать двойные кавычки как часть «значения» каждого параметра.)

Regex r = new Regex(@"(?<function>[\p{L}_]\w*?)\((?<inner>.*?)\)");
Regex inner = new Regex(@",?(?<param>.+?):""(?<value>[^""]*?)""");
string input = "_test0(a:\"lolololol\",b:\"2\") _test1(ghgasghe:\"asjkdgh\")";

var matches = new List<FunctionInfo>();

if (r.IsMatch(input))
{
    MatchCollection mc = r.Matches(input);
    foreach (Match match in mc)
    {
        var l = new List<ParamValue>();

        foreach (Match m in inner.Matches(match.Groups["inner"].Value))
            l.Add(new ParamValue
            {
                Parameter = m.Groups["param"].Value,
                Value = m.Groups["value"].Value
            });

        matches.Add(new FunctionInfo
        {
            FunctionName = match.Groups["function"].Value,
            Values = l
        });
    }
}

Затем вы можете легко получить доступ к коллекции с помощью идентификаторов, таких как FunctionName:

foreach (var match in matches)
{
    Console.WriteLine("{0}({1})", match.FunctionName,
        string.Join(", ", match.Values.Select(val =>
            string.Format("{0}: \"{1}\"", val.Parameter, val.Value))));
}
1 голос
/ 08 сентября 2010

Здесь:

\w[\w\d]*\s*\(\s*(?:(\w[\w\d]*):("[^"]*"|\d+))*\s*\)

Визуализация этого регулярного выражения здесь .

1 голос
/ 08 сентября 2010

Попробуйте это:

^\s*(?<FunctionName>[A-Za-z][A-Za-z_0-9]*)\(((?<parameter>[^:]*):"(?<value>[^"]+)",?\s*)*\)
  • ^\s*(?<FunctionName>[A-Za-z][A-Za-z_0-9]*) соответствует имени функции, ^ означает начало строки, поэтому первый символ в строке должен совпадать. Вы можете сохранить удаление пробелов, если оно вам не нужно, я просто добавил его, чтобы сделать матч немного более гибким.
  • Следующий набор \(((?<parameter>[^:]*):"(?<value>[^"]+)",?)*\) означает захват каждой пары параметр-значение в скобках. Вы должны экранировать скобки для функции, так как они являются символами в синтаксисе регулярных выражений.

Внутри круглых скобок? <> Называются группы захвата, которые, когда они поддерживаются библиотекой, как и в .NET, облегчают захват групп в совпадениях.

0 голосов
/ 08 сентября 2010

Это регулярное выражение проходит все ваши тесты:

^(?<function>[A-Za-z][\w]*?)\(((?<param>[^:]*?):"(?<value>[^"]*?)",{0,1}\s*)*\)$

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

Обратите внимание, что \w обычно включает цифры и не подходит в качестве начального символа имени функции. Ссылка: http://www.regular -expressions.info / charclass.html # стенография

0 голосов
/ 08 сентября 2010

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

Но вот мой быстрый выстрел:

(?<funcName>[A-Za-z_][A-Za-z_0-9]*)
\(
    (?<ParamGroup>
        (?<paramName>[^(]+?)
        :
        "(?<paramValue>[^"]*)"
        ((,\s*)|(?=\)))
    )*
\)

Пробелы есть для лучшей читаемости. Удалите их или установите параметр, чтобы игнорировать пробелы в шаблонах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...