1

我正在尝试做的事情:删除围绕特定未转义字符的最里面的未转义方括号(\是转义)

输入:[\[x\]]\]\[[\[y\]]
在 y 周围查找括号[\[x\]]\]\[\[y\]
时输出:在 x 周围查找括号时输出:\[x\]\]\[[\[y\]]

简而言之,只删除特定字符周围未转义的括号集。

我试过这个 (for y): Regex.Replace(input, @"(?<!\\)\[(.*?(?<!\\)y.*?)(?<!\\)\]",@"$1",但这似乎与第一个未转义[的(在 x 之前)与最后一个匹配]。我想我可以用.否定字符类替换通配符来排除[and ],但是我真正需要否定的是这些的未转义版本,当我尝试(?<!\\)在否定字符类中加入否定的lookbehind 时,我似乎什么都不匹配一点也不。

提前感谢您的时间和精力。

编辑:

澄清一下,未转义方括号的内容可以是任何内容(另一个未转义方括号除外),只要它们包含感兴趣的未转义字符 ( y)。括号中的所有内容应保留。

4

3 回答 3

2

为这个问题编写一个正则表达式可能过于复杂。虽然这个函数有点冗长,但它在概念上很简单并且可以解决问题:

    string FixString(char x, string original)
    {
        int i = 0;
        string s = original;
        while (i < s.Length)
        {
            if (s[i] == x)
            {
                bool found = false;
                for (int j = i + 1; (j < s.Length) && !found; j++)
                {
                    if ((s[j] == ']') &&
                        (s[j-1] != '\\'))
                    {
                        s = s.Remove(j, 1);
                        found = true;
                    }
                }
                if (i > 0)
                {
                    found = false;
                    for (int j = i - 1; (j >= 0) && !found; j--)
                    {
                        if ((s[j] == '[') &&
                            ( (j == 0) ||
                              (s[j - 1] != '\\') ))
                        {
                            s = s.Remove(j, 1);
                            i--;
                            found = true;
                        }
                    }
                }
            }
            i++;
        }

        return s;
    }
于 2010-02-01T22:09:29.510 回答
2

Lookbehind 是这项工作的错误工具。试试这个:

Regex r = new Regex(
  @"\[((?>(?:[^y\[\]\\]|\\.)*)y(?>(?:[^\[\]\\]|\\.)*))\]");

string s1 = @"[\[x\]]\]\[[\[y\]]";
Console.WriteLine(s1);
Console.WriteLine(r.Replace(s1, @"%$1%"));

Console.WriteLine();

string s2 = @"[\[x\]]\]\[[1234(\[abcycba\]\y\y)]";
Console.WriteLine(s2);
Console.WriteLine(r.Replace(s2, @"%$1%"));

结果:

[\[x\]]\]\[[\[y\]]
[\[x\]]\]\[%\[y\]%

[\[x\]]\]\[[1234(\[abcycba\]\y\y)]
[\[x\]]\]\[%1234(\[abcycba\]\y\y)%

(我用括号代替了括号,%而不是删除它们,以便更容易准确地看到要替换的内容。)

(?:\\.|[^y\[\]\\])*匹配零个或多个 (1) 后跟任何字符的反斜杠,或 (2) 不是“y”、方括号或反斜杠的任何内容。如果下一个字符是 'y',它将被消耗并(?:\\.|[^\[\]\\])*匹配任何剩余的字符,直到下一个未转义的括号。在否定字符类中包含两个括号(连同反斜杠)可确保您只匹配最里面的一组未转义的括号。

使用原子组也很重要——即,(?>...); 这可以防止回溯,我们知道这将是无用的,并且当正则表达式用于不包含匹配项的字符串时,这可能会导致严重的性能问题。

另一种方法是使用前瞻来断言“y”的存在,然后使用更简单(?>(?:\\.|[^\[\]\\])*)的方法来使用括号之间的字符。问题是您现在要在字符串上进行两次传递,并且确保前瞻不会看得太远或不够远可能会很棘手。一次性完成所有工作可以更轻松地跟踪您在匹配过程的每个阶段的位置。

于 2010-02-02T01:03:44.133 回答
1

编辑问题后编辑

Regex.Replace(input, @"((?<!\\)\[(?=((\\\[)|[^[])*((?<!\\)y)))|((?<=[^\\]y((\\\]|[^]]))*)(?<!\\)\])","");

我们要匹配要删除的括号:

(?<!\\)\[ - Match is an unescaped left bracket
(?=((\\\[)|[^[])*((?<!\\)y)) - Match is followed by any number of (escaped left brackets or non-left brackets) followed by an unescaped y

| - OR

(?<=[^\\]y((\\\]|[^]]))*) - Match is preceded by unescaped y followed by any number of (escaped right brackets or non-right brackets)
(?<!\\)\] - Match is an unescaped right bracket
于 2010-02-01T21:48:43.837 回答