Regexp:排除一个单词,但包含非标准标点符号

Regexp: excluding a word but including non-standard punctuation

本文关键字:单词 包含 标点符号 非标准 一个 排除 Regexp      更新时间:2023-09-26

我想查找包含按特定顺序排列的单词的字符串,允许在单词之间使用非标准字符,但不包括特定的单词或符号。

我正在使用javascript的replace函数来查找所有实例并放入数组。

所以,我想要select...from,在单词之间除了'from'以外的任何东西。或者我可以把select...fromselect...from (分开,只要我排除嵌套。我认为答案是相同的,即我如何写:找到x而不是y在相同的正则表达式?

从互联网上,我觉得这应该工作:/'bselect'b^(?!from).*'bfrom'b/gi,但这没有找到匹配。

这可以找到所有的select...from: /'bselect'b[0-9a-zA-Z@'(')'[']'s'.'*,%_+-]*?'bfrom'b/gi,但修改它以排除末尾的括号"("会阻止任何匹配:/'bselect'b[0-9a-zA-Z@'(')'[']'s'.'*,%_+-]*?'bfrom'b's*^'(/gi

谁能告诉我如何排除这个正则表达式中的单词和符号?

多谢艾玛

编辑:部分字符串输入:

left outer join [stage].[db].[table14] o on p.Project_id = o.project_id
left outer join
(
select
     different_id
    ,sum(costs) - ( sum(brushes) + sum(carpets) + sum(fabric) + sum(other) + sum(chairs)+ sum(apples) ) as overallNumber
    from 
    (
    select ace from [stage].db.[table18] J 
Javascript:

sequel = stringInputAsAbove;    
var tst = sequel.replace(/'bselect'b['s'S]*?'bfrom'b/gi, function(a,b) { console.log('match: '+a); selects.push(b); return a; });
console.log(selects);

Console.log(select)应该打印一个数字数组,其中每个数字都是select...from的起始字符。这适用于我在info中给出的第二个regexp,打印:[95,251]。你的's' s变体也一样,@stribizhev。

第一个示例^(?!from).*应该做同样的事情,但返回[]。

第三个示例's*^'(应该只返回251,但返回[]。然而,我刚刚注意到,积极的表达's*'(确实给95,所以一些进展!

您的'bselect'b^(?!from).*'bfrom'b正则表达式不像预期的那样工作,因为:

  1. ^这里表示一行的开始,而不是下一部分的否定,所以'bselect'b^表示,select字后跟a的开头线。移除^后,regex开始匹配某些东西(DEMO)但仍然无效。
  2. 在多行文本.*中未经修改将不匹配新行,所以regex将只匹配select...from单行,但是如果你将其更改为(.|'n)*(作为一个简单的示例),它将匹配多行,但仍然无效
  3. *是贪婪的量化,所以它会尽可能地匹配,但如果您使用不情愿的量化*?, regex将首先匹配当from字出现时,int将开始相对返回正确结果。
  4. 'bselect'b(?!from)表示不匹配单独的select字直接跟在单独的from单词后面,所以应该是selectfrom不知何故由单独的单词组成(因为select'bfrom)所以(?!from)不工作,它是多余的

实际上你将得到与Stribizhev给你的非常相似的正则表达式:'bselect'b(.|'n)*?'bfrom'b

在第三个表达式中,您犯了同样的错误:'bselect'b[0-9a-zA-Z@'(')'[']'s'.'*,%_+-]*?'bfrom'b's*^'(使用^作为(我假设)否定,而不是行开头。删除^,您将再次获得相对有效的结果(从selectfrom匹配到关闭旁括号))。

第二个正则表达式的工作原理类似于'bselect'b(.|'n)*?'bfrom'b'bselect'b['s'S]*?'bfrom'b

我写了"相对有效的结果",因为我也认为,用正则表达式解析SQL可能非常复杂,所以我不确定它是否会在每种情况下工作。


您也可以尝试使用正向前看来匹配文本中的位置,例如:

(?='bselect'b(?:.|'n)*?'bfrom'b)

DEMO - ()被添加到regex只是为了返回匹配组的开始索引,所以它会更容易检查它的有效性


正则表达式

我们在字符类中使用^作为否定,例如[^a-z]表示匹配除字母以外的任何内容,因此它将匹配数字,符号,空格等,但不匹配az范围内的字母(看这里)。但这种否定是在单个角色的层面上。如果您使用[^from],它将阻止regex匹配字符f, r, om(演示)。此外,[^from]{4}将避免匹配from,但也会匹配form, morf等。

要通过regex排除整个单词的匹配,您需要使用负查找,如(?!from),如果在给定位置后面有被选中的单词from,则将无法匹配。为了避免匹配包含from的整行,您可以使用^(?!.*from.*).+$ (demo)。

然而,在你的情况下,你不需要使用这种结构,因为如果你用.*?'bfrom替换贪婪量化.*'bfrom,它将匹配这个词的第一次出现。更重要的是,它会带来问题。看看这个正则表达式,它不会匹配任何东西,因为(?!['s'S]*from['s'S]*)不受任何限制,所以只有在select之后没有from时才会匹配,但我们也想匹配from !实际上,这个正则表达式试图匹配并排除from,并且失败。因此,(?!.*word.*)结构可以更好地排除与给定单词匹配的行。

那么,如果我们不匹配匹配片段中的单词该怎么办呢?我认为select'b([^f]|f(?!rom))*?'bfrom'b是一个很好的解决方案。对于([^f]|f(?!rom))*?,它将匹配selectfrom之间的所有内容,但不会排除from

但是如果你想只匹配select...from而不匹配(,那么使用(?!'()是一个好主意。但是在您的regex(多行)中,使用(.|'n)*?['s'S]*?将导致匹配到下一个select...from部分,因为不情愿的量化将改变需要匹配的地方以使整个regex。在我看来,好的解决方案是再次使用:

select'b([^f]|f(?!rom))*?'bfrom'b(?!'s*?'()

不会重叠额外的select..from,如果select...from后面有'(,则不会匹配-在这里检查