in reply to Driving the Engine right off the road

Lookahead/behind are zero-width assertions; you are asserting that after matching ^ (beginning of string), what comes just before that can't be XDG_, and then continuing to match the rest of your regex. There are two problems here: first, the beginning of the string will never follow XDG_, so your assertion will always pass; and second, you will only match if the string ends with _PATH or _PATH followed by a newline, which doesn't meet your requirements.

If perl supported variable length lookbehind, you could use a lookbehind at the end:
/^[_A-Z0-9]+$(?<!^XDG_.*_PATH)/
but it doesn't. So use a lookahead instead, to test that the entire string is the expected characters but doesn't match your exclusion at the beginning:
/^(?!XDG_.*_PATH$)[_A-Z0-9]+$/
or (and this is almost always the more readable approach), do it in code:
/^[_A-Z0-9]+$/ && ! /^XDG_.*_PATH$/

Replies are listed 'Best First'.
Re^2: Driving the Engine right off the road
by swl (Prior) on Aug 24, 2025 at 22:53 UTC
Re^2: Driving the Engine right off the road
by ysth (Canon) on Aug 24, 2025 at 14:58 UTC
    Note that I kept your $ but I hate it, because without /m it is rarely used to intentionally do what it actually does (match either the end of the string or before a newline at the end of a string). If your data has no newlines, use \z (match only at the end of the string). If your data ends with newlines, use \n (or \n\z if your string may have internal newlines that should not match). Then your code doesn't mislead about what the data looks like.

      It's weird. I lost some good habits when I took my 10-year break from programming, and using \z instead of $ in regexen is one of them. Since you pointed it out, I think my fingers will do the right thing from now on. In this case it wouldn't matter because my strings are all keys from %ENV and would never contain an embedded newline. But regaining (and retaining) good coding habits is important.

          – Soren

      never