正则表达式最大和最小之间的战斗

时间:2010-01-05 16:31:26

标签: c# regex

问候,我有以下字符串的文件:

string.Format("{0},{1}", "Having \"Two\" On The Same Line".Localize(), "Is Tricky For regex".Localize());

我的目标是使用两个字符串获得匹配集:

  • 在同一行上有“两个”
  • 对于正则表达而言是棘手的

我目前的正则表达式如下:

private Regex CSharpShortRegex = new Regex("\"(?<constant>[^\"]+?)\".Localize\\(\\)");

我的问题是第一行中的转义引号我最终停在引号处,我得到:

  • 在同一条线上
  • 这种风格很棘手
然而,试图忽略转义的引号却没有成功,因为它让正则表达式变得贪婪而且我得到了

  • 在同一行上有“两个”“.Localize(),”正在使用正则表达式“

我们好像被夹在最大和最小的间隙之间。有什么希望吗?我有一些备份计划。你可以倒退正规吗?这会让事情变得更容易,因为我可以从“()ezilacoL开始。”

修改 澄清。这是我唯一的边缘情况。大多数情况下,字符串独自坐着:

var myString = "Hot Patootie".Localize()

5 个答案:

答案 0 :(得分:1)

更新

我的原始答案(在横向规则下面)有一个错误:正则表达式匹配器尝试从左到右的顺序。将[^"]作为第一个选择允许它使用反斜杠,但是匹配的下一个字符是一个引号,这会阻止匹配继续进行。

不兼容性说明:鉴于下面的模式,perl会回溯到另一个替代方案(转义报价)并成功找到Having \"Two\" On The Same Line案例的匹配项。

修复方法是首先尝试转义报价,然后尝试非报价:

var CSharpShortRegex =
  new Regex("\"(?<constant>(\\\\\"|[^\"])*)\"\\.Localize\\(\\)");

或者如果您更喜欢at-string形式:

var CSharpShortRegex =
  new Regex(@"""(?<constant>(\\""|[^""])*)""\.Localize\(\)");

允许逃跑:

private Regex CSharpShortRegex =
  new Regex("\"(?<constant>([^\"]|\\\\\")*)\"\\.Localize\\(\\)");

应用一级转义以使图案更易于阅读,我们得到

"(?<constant>([^"]|\\")*)"\.Localize\(\)

也就是说,字符串以"个字符开头和结尾,其间的所有字符都是非引号或转义引号。

答案 1 :(得分:1)

这是您需要的正则表达式:

@"""(?<constant>(\\.|[^""])*)""\.Localize\(\)"

测试程序:

使用System; 使用System.Text.RegularExpressions; 使用System.IO;

class Program
{
    static void Main()
    {
        Regex CSharpShortRegex =
            new Regex(@"""(?<constant>(\\.|[^""])*)""\.Localize\(\)");

        foreach (string line in File.ReadAllLines("input.txt"))
            foreach (Match match in CSharpShortRegex.Matches(line))
                Console.WriteLine(match.Groups["constant"].Value);
    }
}

输出:

Having \"Two\" On The Same Line
Is Tricky For regex
Hot Patootie

请注意,我使用@"..."来避免在正则表达式中转义反斜杠。我认为这样可以更容易阅读。

答案 2 :(得分:1)

这个适用于我:

\"((?:[^\\"]|(?:\\\"))*)\"\.Localize\(\)

针对具有各种转义引号的多个字符串在http://www.regexplanet.com/simple/index.html上进行了测试。

看起来我们回答这个问题的大多数人都有同样粗略的想法,所以让我解释一下这个方法(#之后的评论):

\"             # We're looking for a string delimited by quotation marks
(              # Capture the contents of the quotation marks
  (?:          #   Start a non-capturing group
    [^\\"]     #     Either read a character that isn't a quote or a slash
    |(?:\\\")  #     Or read in a slash followed by a quote.
  )*           #   Keep reading
)              # End the capturing group
\"             # The string literal ends in a quotation mark
\.Localize\(\) # and ends with the literal '.Localize()', escaping ., ( and )

对于C#,你需要两次逃避斜杠(凌乱):

\"((?:[^\\\\\"]|(?:\\\\\"))*)\"\\.Localize\\(\\)

标记正确指出此标记与引号之外的转义字符不匹配。所以这是一个更好的版本:

\"((?:[^\\"]|(?:\\")|(?:\\.))*)\"\.Localize\(\)

其削减的等价物:

\"((?:[^\\\\\"]|(?:\\\\\")|(?:\\\\.))*)\"\\.Localize\\(\\)

以相同的方式工作,除了它有一个特殊情况,如果遇到斜杠但它不能匹配\",它只是消耗斜杠和后面的字符并继续前进。


考虑到这一点,最好只在每个斜线上消耗两个字符,这实际上是Mark的答案所以我不会重复它。

答案 3 :(得分:0)

看起来您正在尝试解析代码,因此一种方法可能是动态评估代码:

var cr = new CSharpCodeProvider().CompileAssemblyFromSource(
    new CompilerParameters { GenerateInMemory = true }, 
    "class x { public static string e() { return " + input + "}}");

var result = cr.CompiledAssembly.GetType("x")
    .GetMethod("e").Invoke(null, null) as string;

通过这种方式,您可以处理使用正则表达式处理极其困难的各种其他特殊情况(例如连接或逐字字符串)。

答案 4 :(得分:0)

new Regex(@"((([^@]|^|\n)""(?<constant>((\\.)|[^""])*)"")|(@""(?<constant>(""""|[^""])*)""))\s*\.\s*Localize\s*\(\s*\)", RegexOptions.Compiled);

处理简单和@“”字符串。它还考虑了转义序列。