Как сопоставить строку A, которая не содержит строку A

#c# #regex

#c# #регулярное выражение

Вопрос:

Из .*tan(.*tan(.*)).* и только .*tan(.*tan(.*)).* , я хочу сопоставить внутреннюю tan(.*) .


Регулярное выражение

 tan([0-9a-zA-Z. -*/()![tan]] )
 

Пример

От:

 tan(80.1*tan(81.7 (80.9 81.5))) 81.9
 

Я хочу извлечь внутреннюю:

 tan(81.7 (80.9 81.5))
 

Но не:

 tan(80.1*tan(81.7 (80.9 81.5)))
 

Ответ №1:

Вы можете использовать три регулярных выражения. (Я знаю! Безумие, не так ли?)

Первое извлечение:

 ^tan(.*?tan(.*?).*?)$
 

Затем извлеките:

 ^(?=(tan(.*?))tan(.*?).*$
 

Затем извлеките:

 ^tan(.*?)(?=(.*?).*?))$
 

Если вы используете Perl, это намного проще:

 $mystr =~ s^.*?tan(.*?(tan(.*?)).*?).*$1;
 

Редактировать:

Я не знаю точно, чего вы хотите, но, судя по вашему комментарию к сообщению @Thorbear, я не думаю, что вам следует использовать регулярные выражения. Вы не можете анализировать контекстно-свободные грамматики только с помощью регулярных выражений [C #].

Что вам нужно, так это анализатор выражений, а не регулярное выражение.

Комментарии:

1. это не только два tan, если их много tan, сначала ожидайте получить самый внутренний tan (XXX), почему бы не исключить tan?

Ответ №2:

 static void Main(string[] args){
    var str = "tan(80.1*tan(81.7 (80.9 81.5))) 81.9";

    Console.WriteLine(innerTan(str));
}
static string innerTan(string str){
    const string token = "tan(";
    if(!str.Contains(token))
        return String.Empty;

    var spos = str.IndexOf(token);
    var epos = spos   token.Length;
    var balance = 1;
    for(var i = epos ;i < str.Length;  i){
        switch (str[i]){
        case '(':
              balance;break;
        case ')':
            --balance;break;
        }
        if(balance == 0){
            epos = i;
            break;
        }
    }
    var innerText = str.Substring(spos   token.Length, epos - spos);
    if(innerText.Contains(token))
        return innerTan(innerText);
    else
        return str.Substring(spos, epos - spos   1);
}
 

Комментарии:

1. C # (.NET) Я, вероятно, не стал бы считать, что скобки регулярного выражения сбалансированы.

2. Возможно, невозможно. В регулярных выражениях я не могу сопоставить количество скобок, которые помещаются в левую и правую круглые скобки. (Возможно, Perl может сделать)

Ответ №3:

Немного не уверен в ваших требованиях… но что-то вроде tan(.*?(tan(.*))) сохранит внутренний tan() в $1

Для ваших групп символов вам не нужно экранировать символы [0-9a-zA-Z. */-] , будет достаточно, просто будьте осторожны с тем, где вы размещаете -

Редактировать:
если у вас есть неизвестное количество tan() внутри друг друга, вам понадобится что-то вроде tan((.(?!tan))*?) захвата самого внутреннего. Однако впоследствии вам придется сбалансировать круглые скобки, так как subject like tan(80.1*tan(81.7 (80.9 81.5))) вернет совпадение tan(81.7 (80.9 81.5) . Кроме того, если ваш объект выглядит так tan(80.1*tan(81.7 (80.9 81.5) (80.9 81.5))) , что шаблон не будет захватывать последнее (80.9 81.5) , удаление последнего ? решит эту проблему, но тогда у вас возникнут проблемы с такими объектами, как tan(80.1*tan(81.7 (80.9 81.5))) (80.9 81.5) , поскольку он также захватит последнее выражение.

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

Комментарии:

1. если существует много tan(x tan(x tan (x))), требование состоит в том, чтобы сначала получить самый внутренний tan

2. Вы не можете использовать только регулярные выражения для этого ! Но ваш вопрос все еще неясен.

Ответ №4:

Поскольку я не могу использовать операторы and и not отфильтровывать самые внутренние tan , я, наконец, попробовал:

 public String MatchExtra(string head, string extra)
{
    string result = "";

    if (!head.Contains(extra))
        return head;

    string criteria = extra   "\([a-zA-Z0-9\.\ \-\*\/] \)";
    MatchCollection match1 = Regex.Matches(head, criteria, RegexOptions.IgnoreCase);
    foreach (Match bracket_match in match1)
    {
        if (bracket_match.Success)
        {   // not finish if bracket have bracket
            for (int y = 0; y < bracket_match.Captures.Count; y  )
            {
                string a = bracket_match.Captures[y].ToString();
                string b = bracket_match.Captures[y].ToString().Substring(extra.Length   1, bracket_match.Captures[y].ToString().Length - extra.Length - 2);
                result = MatchExtra(bracket_match.Captures[y].ToString().Substring(extra.Length   1, bracket_match.Captures[y].ToString().Length - extra.Length - 2), extra);
                return resu<
            }
        }
    }

    string criteria2 = extra   "\(.*\)";
    MatchCollection match2 = Regex.Matches(head,  criteria, RegexOptions.IgnoreCase);
    foreach (Match bracket_match in match2)
    {
        if (bracket_match.Success)
        {   // not finish if bracket have bracket
            for (int y = 0; y < bracket_match.Captures.Count; y  )
            {
                string a = bracket_match.Captures[y].ToString();
                string b = bracket_match.Captures[y].ToString().Substring(extra.Length 1, bracket_match.Captures[y].ToString().Length - extra.Length -2);
                result = MatchExtra(bracket_match.Captures[y].ToString().Substring(extra.Length 1, bracket_match.Captures[y].ToString().Length - extra.Length-2), extra);
                return resu<
            }
        }
    }
    return resu<
}