我在super user发布了此问题,建议我在stackoverflow上发布此问题。
我真的很喜欢vim,今天我遇到了有趣的问题,我认为可以通过regexp完成,但我不能形成正确的问题。
我有一个非常大的sql文件。它整合了许多不同的查询。文件包含以下内容:
select * from hr.employees, oe.orders, oe.order_items
select * from hr.employess, oe.orders, hr.job_history
select * from oe.customers, oe.orders, hr.employees
select * from hr.employees, hr.departments, hr.locations
如何仅选择与该行只有hr.
匹配的那些行?例如,上面它将是第一行和第三行。
答案 0 :(得分:5)
当然,可以匹配这些线。这种模式匹配:
^\%(\%(hr\.\)\@!.\)*hr\.\%(\%(hr\.\)\@!.\)*$
有些人喜欢使用非常神奇的开关\v
来减少反斜杠的数量。然后相同的模式变为
\v^%(%(hr\.)@!.)*hr\.%(%(hr\.)@!.)*$
(这里我使用了非捕获括号\%(...\)
,但捕获括号\(...\)
也可以正常工作。)
问题是:你想用这些线做什么?删除它们?
在这种情况下,您可以使用:global
命令:
:g/\v^%(%(hr\.)@!.)*hr\.%(%(hr\.)@!.)*$/d
的更多信息
:h :global
:h /\v
:h /\%(
:h /\@!
答案 1 :(得分:3)
检查行是否仅包含hr.
使用正则表达式
^(?=.*\bhr\.)(?!.*\bhr\..*\bhr\.).*
修饰符的 m
。我建议使用grep -P
实用程序。
答案 2 :(得分:3)
为此,您需要将负向lookbehind 与否定先行断言相结合;即,当前匹配的模式在同一行之前或之后不得匹配。在Vim中,这些原子的原子分别是\@<!
和\@!
。
因此,找到一次X的模式就是:
/\%(X.*\)\@<!X\%(.*X\)\@!/
应用于您的模式hr.
:
/\%(hr\..*\)\@<!hr\.\%(.*hr\.\)\@!/
答案 3 :(得分:0)
像这样的问题我总是觉得更容易将它分成正则表达式的多种用法。如果我要用grep过滤这个,我会这样做:
grep "hr\." foo.sql
这给了我所有的行“hr。”,甚至是带有两个的行。
现在我再次通过grep管道输出并要求它忽略hr.
出现两次的行:
grep "hr\." foo.sql | grep -v "hr\..*hr\."
我知道你在谈论vim,但我正在展示可能有用的替代品,可能会更清楚。