【问题标题】:Regex to detect a pattern outside double quotes正则表达式检测双引号外的模式
【发布时间】:2016-01-20 09:32:09
【问题描述】:

我有一个类似

的字符串
FIND files where file2=29 AND file32="12" OR file623134="file23"

用户输入此文本以搜索他/她的数据。这由应用程序转换为 SQL 查询。

例如:FIND 替换为SELECT 和带有模式file[number] 的字符串(例如:file2file32file623134,如上面的字符串所示。)转换为FILE_ID=[number] AND FILE_VALUE=[value of FILE[number] .生成的 SQL 查询将是:

SELECT * FROM [FILES] WHERE (FILE_ID=2 AND FILE_VALUE=29) AND (FILE_ID=32 AND FILE_VALUE="12") OR (FILE_ID=623134 AND FILEVALUE="file23")

到目前为止,在其他 SO 问题的帮助下,我所取得的成就是使用以下正则表达式检测双引号之外的字符串:

(?<![\S"])([^"\s]+)(?![\S"])

一切正常。但是由于我对正则表达式缺乏了解,我无法在这个正则表达式中找到可以放置file[0-9] 模式的位置。请告诉我如何才能做到这一点?

如果可能的话,请告诉我如何从这些模式中提取值并将它们替换为相应的值,例如 file123=2(FILE_ID=123 AND FILE_VALUE=2)

【问题讨论】:

  • 如果我理解正确,您想捕获“文件”后面的数字和值。请试试这个:Regex101
  • 你是用 C# 还是 javascript 解决这个问题?
  • @NigelThorne C# 是首选,以便我可以在服务器端进行转换。但如果有人在 JavaScript 中有解决方案,那也是可以接受的。
  • 检查 regexper.com 以获得正则表达式的可视化表示。它被称为铁路图,就像你想象的那样,你是一列从一端开始的火车,你只能转弯。
  • 这是C# demo,如果它按预期工作,请告诉我。

标签: javascript c# .net regex string


【解决方案1】:

这是另一种两步法:

  • 获取带有 ID 的键值对并使用反向引用替换
  • 将开头部分(文字 "FIND files where")替换为另一个文字 "SELECT * FROM [FILES] WHERE"

C# demo:

var str = "FIND files where file2=29 AND file32=\"12\" OR file623134=\"file23\"";
var rx = new Regex(@"\bfile(\d+)=""?(\w+)""?");
var result = rx.Replace(str, "(FILE_ID=$1 AND FILE_VALUE=$2)")
              .Replace("FIND files where", "SELECT * FROM [FILES] WHERE");
Console.WriteLine(result);

结果:

SELECT * FROM [FILES] WHERE (FILE_ID=2 AND FILE_VALUE=29) AND (FILE_ID=32 AND FILE_VALUE=12) OR (FILE_ID=623134 AND FILE_VALUE=file23)

正则表达式分解:

  • \bfile - 文字 file 前面没有单词字符的文字
  • (\d+) - 1 个或多个数字被捕获到第 1 组
  • = - 文字 =
  • "? - 1 或 0 双引号
  • (\w+) - 第二个捕获组,由 1 个或多个字母数字符号(字母、数字或下划线)组成
  • "? - 1 或 0 双引号

【讨论】:

  • 我非常喜欢这个。它不保证格式是有效的,这可能会让你容易受到 sql 攻击。但所有的答案可能都会有这个问题。在这种情况下,字符串匹配不能确保字符串被关闭,或者处理字符串中的空格或字符串中的转义字符。不过很好......非常简单。
  • 非常感谢。我在所有条件下都对其进行了测试,并且有效。但是,如果您或您 @NigelThorne 可以解决有关 SQL 攻击的问题。我删除了SELECT 语句,现在只转换条件,因为SELECT 语句是不变的。我还找到了一种在传递值时使用参数来避免 SQL 注入的方法。但是客户端仍然可以在结果语句中输入 SQL 语句。你能告诉我一个检测 SQL 子句的正则表达式,比如SELECT,UPDATE,INSERT,DELETE,DROP 和其他双引号之外的子句吗?否则没关系,我会弄清楚的。 :)
  • 非常感谢您。你刚刚给了我足够的氧气。现在我可以游得很深了。 ;)
【解决方案2】:

您可以使用以下命令检测您的文件字符串:

file([0-9]+)=\"([0-9]+)\"

这个正则表达式返回 3 个字符串,整个匹配,字符串中的第一个数字和第二个数字。

我希望这是你所期望的。

但是我认为您在使用正则表达式时错过了一点:

在多个标记周围放置括号以将它们组合在一起。然后,您可以将量词应用于组。例如。设定值)?匹配 Set 或 SetValue。

括号创建一个捕获组。上面的例子有一个组。匹配后,如果 Set 匹配,第一组不包含任何内容。如果 SetValue 匹配,它包含 Value。如何访问组的内容取决于您使用的软件或编程语言。零组始终包含整个正则表达式匹配。

来自:http://www.regular-expressions.info/quickstart.html

因此,您必须为整行定义一个正则表达式,并为要提取的每个子字符串创建一个匹配组。

【讨论】:

  • 感谢@baddger964 的快速入门指南。 :)
【解决方案3】:

喜欢这个

<div id="date">file23="125"</div>

js

var data =$('#date').text();
var arr = data.split('=');
var val1 =arr[0];
val1 =  val1.replace(/[0-9]/g,'');
var val2 =arr[0];
val2 =  val2.replace(/[a-zA-Z]/g,'');
var val = arr[1];
val = val.replace(/[&\/\\#,+()$~%.'":*?<>{}]/g,'');
$("#date").html("<span>"+val1 + "</span></br>" + "<span> id="+val2 + "</span></br>" + "<span> value="+val + "</span></br>" );     

输出

file
id=23
value=125

jsfiddle click here

【讨论】:

    【解决方案4】:

    假设我们匹配FIND files where file2=29 AND file32="12" OR file623134="file23"

    作为解释,我将分步进行。

    显然,与字符串完全匹配的正则表达式会匹配。

    FIND files where file2=29 AND file32="12" OR file623134="file23"
    

    首先让我们决定我们要从中读取哪些位...并使其可访问。

    FIND (files) where file(2)=(29) AND file(32)=("12") OR file(623134)=("file23")
    

    在这里,我们在要读取的所有位周围加上括号。这将这些位定义为“捕获组”。在 C# 中,我们可以给它们命名。我们稍后会这样做。

    现在...让我们概括这个正则表达式,以便它匹配更多示例...键是数字,因此我们可以使用[0-9]+ 捕获它们。这意味着match a character in the range 0 to 9, at least once

    FIND (files) where file([0-9]+)=(29) AND file([0-9]+)=("12") OR file([0-9]+)=("file23")
    

    好的..现在值...这里有些是字符串..让我们匹配那些...

    字符串是不是 " 被 '"' 或 "[^"]+" 包围的东西 (注意.. 加号表示我们不能匹配空字符串,因为我们至少需要一个字符。* 可以让您匹配空字符串。)

    FIND (files) where file([0-9]+)=(29) AND file([0-9]+)=("[^"]+") OR file([0-9]+)=("[^"]+")
    

    这个例子中的一个值是一个数字。所以我们假设它们可以是整数。

    FIND (files) where file([0-9]+)=([0-9]+) AND file([0-9]+)=("[^"]+") OR file([0-9]+)=("[^"]+")
    

    第一个例子没有什么特别的。所以我们假设所有的值都可以是字符串或整数。要创建两个选项,我们使用| 选项匹配器。 (现在..我猜你在屏幕上大喊“不,它们可以是任何东西......不仅仅是字符串和数字”,但没关系。我稍后也会处理。)

    FIND (files) where file([0-9]+)=("[^"]+"|[0-9]+) AND file([0-9]+)=("[^"]+"|[0-9]+) OR file([0-9]+)=("[^"]+"|[0-9]+)
    

    现在...我们这里有很多重复...最后一部分是相同的,除了一个有“OR”而另一个有“AND”。这很重要......我们想知道operator 正在使用什么......所以让我们也捕捉一下。

    FIND (files) where file([0-9]+)=("[^"]+"|[0-9]+) (AND) file([0-9]+)=("[^"]+"|[0-9]+) (OR) file([0-9]+)=("[^"]+"|[0-9]+)
    

    现在我们可以通过删除最后一部分并说它是前一个键/值对的重复来排除重复。

    FIND (files) where file([0-9]+)=("[^"]+"|[0-9]+)( (AND|OR) file([0-9]+)=("[^"]+"|[0-9]+))*
    

    我添加了一个“*”,因为表达式的最后一部分可以根据需要重复多次,或者根本不存在。

    现在...如果我们想处理任何值、浮点数、时间等,我们要么需要为每个匹配,要么需要一个通用的“任何”匹配器。两者都有缺点。如果我们明确匹配所有类型,我们还有更多工作要做。如果我们不这样做,那么我们需要对“我们如何知道值何时完成?”做出一些假设

    假设我们假设值后面会有空格。然后我们可以匹配所有字符,直到我们点击空格...[^\s]+

    FIND (files) where file([0-9]+)=([^\s]+)( (AND|OR) file([0-9]+)=([^\s]+))*
    

    但是现在.. 如果该值是一个字符串,并且它包含空格,它会中断。 我们可能想单独处理字符串来解决这个问题。

    FIND (files) where file([0-9]+)=("[^"]+"|[^\s]+)( (AND|OR) file([0-9]+)=("[^"]+"|[^\s]+))*
    

    "[^"]+" 不处理字符串中的转义字符。更好的匹配器是"(\\"|[^"])+",它表示引用,然后重复转义引用或非引用,然后引用。使用它会为您的表达式添加一个新的捕获组。我们不需要那个,所以我们可以通过在括号内添加?: 来告诉它不要捕获这个组。例如"(?:\\"|[^"])+"

    FIND (files) where file([0-9]+)=("(?:\\"|[^"])+"|[^\s]+)( (AND|OR) file([0-9]+)=("(?:\\"|[^"])+"|[^\s]+))*
    

    正如我所提到的......在 C# 中,您可以命名捕获组。为此,您可以在组内添加 ?&lt;name&gt;

    FIND (?<table>files) where file(?<key>[0-9]+)=(?<value>"(?:\\"|[^"])+"|[^\s]+)( (?<operator>AND|OR) file(?<key>[0-9]+)=(?<value>"(?:\\"|[^"])+"|[^\s]+))*
    

    这个表达式中仍然存在重复。但如果我们把它去掉,我们将允许无效的表达式匹配。例如。

    FIND (?<table>files)( (?<operator>AND|OR|where) file(?<key>[0-9]+)=(?<value>"(?:\\"|[^"])+"|[^\s]+))+
    

    这将允许FIND files AND file2="test" 匹配.. 这并不是您真正想要的,但可能已经足够了。

    我可能只是使用字符串 concat 来删除重复,

    var pair = @"(?<pair>file(?<key>[0-9]+)=(?<value>"(?:\\\"|[^\"])+\"|[^\s]+))";
    var query = @"FIND (?<table>files) where "+pair+"( (?<operator>AND|OR) "+pair+")*";
    var ex = new Regex(query);
    

    或者只是进行代码检查以确保第一个运算符是“where”

    var query = @"FIND (?<table>files)(?<condition> (?<operator>AND|OR|where) file(?<key>[0-9]+)=(?<value>"(?:\\\"|[^\"])+\"|[^\s]+))+";
    var ex = new Regex(query);
    var match = ex.Match(...);
    ... match.Groups["table"].Value ... 
    

    您现在可以匹配一个字符串,遍历“条件”组并询问他们的operator,key, andvalue`。

    How do I access named capturing groups in a .NET Regex?

    【讨论】:

    • 感谢@Nigel 对这个过程的精彩分解。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-02
    • 1970-01-01
    • 2011-09-15
    • 2019-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多