不以给定后缀结尾的字符串的正则表达式


188

我无法找到合适的正则表达式来匹配以某种条件结尾的任何字符串。例如,我不希望匹配以结尾的任何内容a

这个匹配

b
ab
1

这不匹配

a
ba

我知道正则表达式应该$以标记结束而告终,尽管我不知道该怎么做。

编辑:原始问题似乎不是我的案例的合法例子。那么:如何处理多个字符?说什么不以ab

我已经可以使用以下线程解决此问题:

.*(?:(?!ab).).$

尽管这样做的缺点是,它与一个字符的字符串不匹配。


5
不是链接问题的重复-与字符串中任何地方匹配相比,仅针对结尾匹配需要不同的语法。只需在此处查看最佳答案即可。
贾斯汀,2015年

我同意,这不是链接问题的重复项。我想知道如何删除上面的“标记”吗?
艾伦·卡布雷拉

我看不到这样的链接。
艾伦·卡布雷拉

Answers:


249

您没有给我们提供语言,但是如果您的正则表达式风味支持不在assert 后面,那么您需要:

.*(?<!a)$

(?<!a)是否定式后置断言,可确保在字符串(或带m修饰符的行)结尾之前没有字符“ a”。

看到这里Regexr

您还可以轻松地用其他字符扩展它,因为这会检查字符串并且不是字符类。

.*(?<!ab)$

这将匹配不以“ ab”结尾的任何内容,请在Regexr上查看


1
我不知道RegexPAL,但是regexes在所有语言中都不同,而后向断言是一项并非所有人都支持的高级功能。
斯玛

7
regexpal是一个基于javascript的正则表达式测试器,并且javascript不支持后向断言,这令人遗憾
HamZa 2013年

regexr(javascript)不支持Lookbehinds
Stealth Rabbi

1
JS中缺乏后顾之忧让我哭了。如果您正在服务器端运行,虽然可以在NPM上使用PCRE模块或类似的方法直接使用它们(这是一组绑定,所以我认为您不能在前端使用它)
Eirik Birkeland

更多类型的先行/后备断言:stackoverflow.com/q/2973436/12484
乔恩·施耐德

76

使用not^)符号:

.*[^a]$

如果将^符号放在方括号的开头,则表示“除方括号外的所有内容”。$仅仅是末日的锚。

对于多个字符,只需将它们全部放在自己的字符集中:

.*[^a][^b]$

1
+1,但请注意,该字符串与空字符串不匹配(可能不符合预期),因此其含义是“不在括号中的任何字符”。
弗雷德·福

3
@ 0A0D:包含空格的字符串不是空字符串。
弗雷德·福

7
@ 0A0D实际上,这不值得辩论,这是事实
tckmn

8
@Doorknob:与ae或不匹配cb
弗雷德·福

1
不,这也不允许“ acb”。
Menno

49

要搜索不以“ .tmp”结尾的文件,我们使用以下正则表达式:

^(?!.*[.]tmp$).*$

使用Regex Tester进行测试后得出以下结果:

在此处输入图片说明


1
有趣的是,任何想法为何^.*(?![.]tmp$)可行,为什么不可行?
卢卡斯Zaroda

4
您的早期版本.*已经与整个字符串匹配,因此其余的排除项不再起作用。
FiveO

就我的目的而言,这行得通,而其他答案却没有。谢谢!
大卫·莫里茨

8
.*[^a]$

上面的正则表达式将匹配不以结尾的字符串a


我扩展了我的问题,因为原始示例似乎并不完全符合我的情况。你能解决吗?
Menno

5

试试这个

/.*[^a]$/

[]表示一个字符类和^反转字符类匹配的一切,但一个a


1

这个问题很老,但我找不到更好的解决方案,我在这里发布了我的问题。查找所有USB驱动器,但不列出分区,从而从结果中删除“ part [0-9]”。我最终做了两次grep,最后一次否定了结果:

ls -1 /dev/disk/by-path/* | grep -P "\-usb\-" | grep -vE "part[0-9]*$"

结果在我的系统上:

pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0

如果我只想要分区,我可以做:

ls -1 /dev/disk/by-path/* | grep -P "\-usb\-" | grep -E "part[0-9]*$"

我在哪里:

pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0-part1
pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0-part2

当我这样做时:

readlink -f /dev/disk/by-path/pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0

我得到:

/dev/sdb

1

如果可以使用环视,则可接受的答案很好。但是,还有另一种方法可以解决此问题。

如果我们看这个问题广泛提出的正则表达式:

.*[^a]$

我们将发现它几乎可以正常工作。它不接受空字符串,这可能有点不方便。但是,仅处理一个字符时这是一个小问题。但是,如果我们要排除整个字符串,例如“ abc”,则:

.*[^a][^b][^c]$

不会的 例如,它将不接受交流电。

但是,有一个简单的解决方案。我们可以简单地说:

.{,2}$|.*[^a][^b][^c]$

或更广义的版本:

.{,n-1}$|.*[^firstchar][^secondchar]$ 其中n是你想禁止(为一个字符串的长度abc是3),并且firstcharsecondchar......首先,你的字符串的第二个......第n个字符(abc这将是a的话b,那么c)。

这是从一个简单的观察结果得出的,即,比我们不允许的文本短的字符串不能包含此文本。因此,我们可以接受任何较短的内容(“ ab”不是“ abc”),也可以接受足够长的内容以供我们接受但不包含结尾。

这是find的示例,该示例将删除所有非.jpg的文件:

find . -regex '.{,3}$|.*[^.][^j][^p][^g]$' -delete


.{,2}$|.*[^a][^b][^c]$不匹配ccc
psalaets

0

任何匹配以---结尾的东西,.*a$所以当您匹配正则表达式时,取反条件,或者您也可以在.*[^a]$其中[^a]意味着not a


0

如果您使用grepsed语法会有所不同。请注意,连续[^a][^b]方法在这里不起作用:

balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n'
jd8a
8$fb
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a]$"
8$fb
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b]$"
jd8a
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^c]$"
jd8a
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a][^b]$"
jd8a
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a][^c]$"
jd8a
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a^b]$"
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a^c]$"
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b^c]$"
jd8a
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b^c^a]$"

FWIW,我在Regex101中发现了相同的结果,我认为这是JavaScript语法。

错误:https//regex101.com/r/MJGAmX/2
好:https//regex101.com/r/LzrIBu/2

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.