regex 正则表达式匹配Postgres“操作符名称”规则

ybzsozfc  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(126)

我尝试(但失败了)编写一个JavaScript正则表达式来匹配PostgreSQL * 运算符名称 *,在文档中定义为:
运算符名称是由以下列表中最多NAMEDATALEN(默认为63)个字符组成的序列:

+ - * / < > = ~ ! @ # % ^ & | ` ?

但是,对操作符名称有一些限制:

  • --和/* 不能出现在操作符名称的任何地方,因为它们将被视为注解的开始。
  • 多字符运算符名称不能以+或-结尾,除非该名称还包含以下字符中的至少一个:
! @ # % ^ & | ` ?

例如,@-是允许的运算符名称,但 *-不是。这个限制允许PostgreSQL解析SQL兼容的查询,而不需要在标记之间使用空格。
除了Regex-noob:

[\+\-\*\/\<\>\=\~\!\@\#\%\^\&\|\`\?]+

我很难得到任何进一步的失败,特别是 --/*不能出现在匹配的字符串” 的要求。我试过把Regular expression to match a line that doesn't contain a word装进去,但没有成功。
在一个正则表达式中实现这一切可能吗?(它在https://github.com/no-context/moo中工作,所以没有机会退回到常规JS)。

非常感谢您的任何建议!

我试过像(?!.*\-\-)[\+\-\*\/\<\>\=\~\!\@\#\%\^\&\|\这样的东西?]+`,但无济于事。

lzfw57am

lzfw57am1#

这个正则表达式将从多行字符串中捕获运算符名称。

/(?:^|[\t ])(?!\S*?(?:--|\/\*))(?![+\-*\/<>=]+[+\-](?=[\s,]))([+\-*\/<>=~!@#%\^&|`?]{1,63})/gm

细分:

(?:^|[\t ])           <- Operator name is at start of line or is preceded by whitespace.
(?!\S*?(?:--|\/\*))   <- It may not contain "--" or "/*"
                         The `\S` is so we stop if we hit a space.
(?![+\-*\/<>=]+[+\-](?=[\s,]))  
                      <- May not end in "+" or "-" if missing certain characters.
                         Determine end of operator by looking for whitespace or comma.
                         Class has all allowed chars minus ones that MUST be present.
([+\-*\/<>=~!@#%\^&|`?]{1,63})
                      <- Contains a sequence of 1 to 63 of a set of allowed characters.

根据以下数据进行测试:

[GOOD]
-
+ +
* *<
/ < > >*
= ~ !
@ # % ^
& | < >
*->

[BAD]
--
/*
+--
@/*
*-
<+
++
*-,

[MIX]
!!@ #/*
#/* !!@
NEGATOR = !==,
!==,*-, #-

定义这些运算符的边界以确定最后一个字符的挑战之一是,您不能使用单词边界符号\b,它查找单词和非单词字符之间的转换,因为我们的运算符是由非单词字符组成的。

dgenwo3n

dgenwo3n2#

首先,在一个字符类中,除了-(以及^,如果它在开头的话)之外,没有一个需要反斜杠转义,所以你可以简化为

/[+\-*\/<>=~!@#%^&|`?]+/

为了避免匹配注解,最简单的解决方案是lookahead:

/(?:(?!--|\/\*)[+\-*\/<>=~!@#%^&|`?])+/

但是你也可以把它拼出来,比如“-后跟一个除了-之外的有效字符,或者/后跟一个除了-之外的有效字符,或者除了-/ 之外的有效字符",但是由于重复仍然没有形成禁止的模式,这很快就变得复杂了。
对于“* 不能以+-结尾,除非它还包含至少一个[...]*",您也可以使用lookaround:

/(?=.*[~!@#%^&|`?]|.*[^+-]$)(?:(?!--|\/\*)[+\-*\/<>=~!@#%^&|`?])+/

但是如果您想将其用于lexer,$锚可能无法工作,因此您需要使用

/(?:(?!--|\/\*)[+\-*\/<>=~!@#%^&|`?])+(?<![+-])|[+-]|(?:(?!--|\/\*)[+\-*\/<>=~!@#%^&|`?])*[~!@#%^&|`?](?:(?!--|\/\*)[+\-*\/<>=~!@#%^&|`?])*/

相关问题