ChatGPT解决这个技术问题 Extra ChatGPT

Regex for string not ending with given suffix

I have not been able to find a proper regex to match any string not ending with some condition. For example, I don't want to match anything ending with an a.

This matches

b
ab
1

This doesn't match

a
ba

I know the regex should be ending with $ to mark the end, though I don't know what should preceed it.

Edit: The original question doesn't seem to be a legit example for my case. So: how to handle more than one character? Say anything not ending with ab?

I've been able to fix this, using this thread:

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

Though the downside with this is, it doesn't match a string of one character.


s
stema

You don't give us the language, but if your regex flavour support look behind assertion, this is what you need:

.*(?<!a)$

(?<!a) is a negated lookbehind assertion that ensures, that before the end of the string (or row with m modifier), there is not the character "a".

See it here on Regexr

You can also easily extend this with other characters, since this checking for the string and isn't a character class.

.*(?<!ab)$

This would match anything that does not end with "ab", see it on Regexr


I don't know RegexPAL, but regexes are different in all languages and lookbehind assertions are an advanced feature that is not supported by all.
regexpal is a javascript based regex tester and javascript doesn't support lookbehind assertions which is sad
Lookbehinds are not supported on regexr (javascript)
Lack of lookbehinds in JS make me cry. If you're doing server-side though you can probably use the PCRE module on NPM or similar to use them directly (it's a set of bindings so I don't think you can use it front-end)
More types of lookahead / lookbehind assertions: stackoverflow.com/q/2973436/12484
C
Community

Use the not (^) symbol:

.*[^a]$

If you put the ^ symbol at the beginning of brackets, it means "everything except the things in the brackets." $ is simply an anchor to the end.

For multiple characters, just put them all in their own character set:

.*[^a][^b]$

+1, with the caveat that this does not match the empty string (which may or may not be as intended), so the meaning is rather "any character that is not in the brackets".
@0A0D: a string containing whitespace is not an empty string.
@0A0D Actually, that's not up for debate, that's a fact
@Doorknob: that doesn't match ae or cb.
Nop, this wouldn't allow "acb" either.
F
FiveO

To search for files not ending with ".tmp" we use the following regex:

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

Tested with the Regex Tester gives following result:

https://i.stack.imgur.com/itjXj.jpg


This is interesting, any idea why this works and why ^.*(?![.]tmp$) doesn't?
Your early .* does already match the whole string, so the remaining exclusion does not work anymore.
For my purposes, this worked and the other answers didn't. Thanks!
A bit late to reply, I know, but for anyone else wondering, as I was, regarding @ŁukaszZaroda question.. it could be because of end of line characters ("\n" and "\r")
K
Kent
.*[^a]$

the regex above will match strings which is not ending with a.


I've extended my question since the original example didn't seem to fully match my case. Can you solve it?
J
JesperE

Try this

/.*[^a]$/

The [] denotes a character class, and the ^ inverts the character class to match everything but an a.


M
MatthewRock

The accepted answer is fine if you can use lookarounds. However, there is also another approach to solve this problem.

If we look at the widely proposed regex for this question:

.*[^a]$

We will find that it almost works. It does not accept an empty string, which might be a little inconvinient. However, this is a minor issue when dealing with just a one character. However, if we want to exclude whole string, e.g. "abc", then:

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

won't do. It won't accept ac, for example.

There is an easy solution for this problem though. We can simply say:

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

or more generalized version:

.{,n-1}$|.*[^firstchar][^secondchar]$ where n is length of the string you want forbid (for abc it's 3), and firstchar, secondchar, ... are first, second ... nth characters of your string (for abc it would be a, then b, then c).

This comes from a simple observation that a string that is shorter than the text we won't forbid can not contain this text by definition. So we can either accept anything that is shorter("ab" isn't "abc"), or anything long enough for us to accept but without the ending.

Here's an example of find that will delete all files that are not .jpg:

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


.{,2}$|.*[^a][^b][^c]$ doesn't match ccc
t
tombert

The question is old but I could not find a better solution I post mine here. Find all USB drives but not listing the partitions, thus removing the "part[0-9]" from the results. I ended up doing two grep, the last negates the result:

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

This results on my system:

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

If I only want the partitions I could do:

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

Where I get:

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

And when I do:

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

I get:

/dev/sdb

B
Bill

Anything that matches something ending with a --- .*a$ So when you match the regex, negate the condition or alternatively you can also do .*[^a]$ where [^a] means anything which is not a


a
abalter

If you are using grep or sed the syntax will be a little different. Notice that the sequential [^a][^b] method does not work here:

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, I'm finding the same results in Regex101, which I think is JavaScript syntax.

Bad: https://regex101.com/r/MJGAmX/2
Good: https://regex101.com/r/LzrIBu/2