【问题标题】:Match string only if a word in the string does not exist仅当字符串中的单词不存在时才匹配字符串
【发布时间】:2013-02-11 06:45:51
【问题描述】:

我正在尝试从 SQL 脚本中提取表名。我有以下字符串:

from db1.tableX tbx1 --quantity table
inner join tableY tbx2  on tbx1.xyz=tbx2.xyz

我不想匹配这个字符串,因为tabley 没有以数据库名称为前缀。我试图做到这一点的方法是在数据库名称之前的字符串中检测单词“on”。

我的正则表达式匹配tablex,但也匹配tbx1,我不希望我的表达式匹配。

我希望它只在这种情况下匹配。

from db1.tableX tbx1 --quantity table
inner join db1.tableY tbx2 on tbx1.xyz = tbx2.xyz

我的正则表达式应该给我tableXtableY,因为它们以数据库名称为前缀。

这是我的表达:

(insert\s+into|from|inner\s+join|left\s+outer\s+join|join)\s+[\sa-zA-Z0-9_$#-]*\.\s*(?<table>[a-zA-Z0-9_]+)(?=\s+[a-zA-Z0-9_$#-]+)*

【问题讨论】:

  • 我不清楚这两种情况之间的区别。唯一的区别在于数据库名称(db1 而不是 dbo)。你还说你尝试检测“on”这个词;我在你的正则表达式中没有看到它。
  • 我的帖子由 abatishchev 编辑。两者之间的区别在于第一种情况,另一种情况是,在第一种情况下,tableY 没有以数据库名称为前缀(我不确定管理员为什么编辑该帖子),在第二种情况下,表的前缀为一个数据库名。在第一种情况下,我不想匹配 tableY,因为它没有以数据库名称为前缀。
  • 如果你有一个数据库名称,那么 SQL-Server 的正确语法应该是 database.owner.tabledatabase..table,即:db1.dbo.tabledb1..table
  • tableY 在这种情况下是 teradata 中的易失性表。它不需要前缀,我不想匹配它

标签: c# sql regex negative-lookbehind


【解决方案1】:

你可以简化你的表达方式

(?<=\b(from|join)\s+[a-zA-Z0-9_$#-]*\.\s*)[a-zA-Z0-9_]+

它将直接生成表名,而无需使用命名组。我正在使用模式

(?<=prefix)find

这只会返回“find”部分作为匹配值。我使用“from”或“join”作为前缀,后跟数据库名称、点和可能的空格。

\b 是单词的开头或结尾。

最后一部分[a-zA-Z0-9_]+是表名。

你是否有内连接、外连接等都没有区别,所以我放弃了这个区别。

评论很难被发现,因为它们可以包含任何内容并且可以出现在任何地方。还有两种类型的 cmets -- Until end of line\* ... *\

您可以尝试像这样检测 cmets 和空格

(\s|--.*?$|\\\*.*?\*\\)+

请注意,退格和星号必须转义,因此\* 变为\\\**\ 变为\*\\

$ 表示行尾。 .* 之后的 ? 确保不会同时跳过几个 cmets,从而跳过它们之间有意义的文本。

这在大多数情况下都有效;但是,类似结构的注释可以包含在字符串文字中:SELECT 'hello -- world' AS greeting FROM ...。这不是评论!如果没有对 SQL 文本的完整语法分析,您将无法涵盖所有​​可能的情况。但是你不能用正则表达式来做到这一点。正则表达式有其局限性。

【讨论】:

  • 奥利弗,您的解决方案似乎运行良好。你能快速解释一下发生了什么吗?
  • 奥利弗,它几乎成功了。它不起作用的一个地方是当我在该内部联接语句之后添加了 cmets 时,例如......从 db1.tableX tbx1 --quantity table inner join --inventory table db1.tableY tbx2 on tbx1.xyz = tbx2.xyz 我在字符类中放了一个 \s
  • 感谢奥利弗的帮助。我了解正则表达式的局限性。我在其他帖子上看到过建议使用 SQL 解析器。但是,这是一个付费应用程序,在这一点上,这是毫无疑问的。我不是想建立任何花哨的东西,我只是想在这里探索一些东西。您的帮助非常宝贵。
【解决方案2】:

一步一步:

1) http://regexr.com?33tto

我不知道你为什么在比赛结束时设置了前瞻。我认为你不需要它,所以我删除了它。

2) http://regexr.com?33ttr

现在我们解决了您指出的问题。问题是在匹配[\sa-zA-Z0-9_$#-]* 的数据库名称中,您已将空格作为有效字符包含在内。我也删除了。

3)http://regexr.com?33ttu

这是理想的结果吗?

【讨论】:

  • 我放 \s 的原因是我可能会遇到这样的情况,即在内部连接语句之后的脚本中会有注释.. 例如。 from db1.tableX tbx1 --quantity table inner join --inventory table db1.tableY tbx2 on tbx1.xyz = tbx2.xyz
  • 这对于单个正则表达式是不可能的,除非您可以“预测”cmets 的位置。你可以吗?如果没有,您将不得不链接多个正则表达式的匹配和过滤。
  • 同意你的说法
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-27
  • 1970-01-01
  • 1970-01-01
  • 2022-11-19
  • 2023-03-11
相关资源
最近更新 更多