A class that starts with a bang or a caret means the opposite - match any one character that is not in the set. Today the scanner reads that leading marker and inverts its verdict.
Make a leading bang or caret negate a character class.
A class can be flipped: if the character right after the [ is a ! (the POSIX
spelling) or a ^ (the common alternative), the class matches any single character
that is not in the set. So [!abc] matches d but not a, and [^0-9]
matches any non-digit. It still consumes exactly one character - negation changes
which characters pass, not how many.
The implementation is a marker check and a final flip: note the leading ! or ^,
skip it, scan the members exactly as before (ranges included, so [!a-z] negates
the whole span), and invert the result at the end. Because the flip happens after
the normal membership test, everything you have already built - single members and
ranges - keeps working unchanged inside a negated class.
// right after the opening '[', check for a negation markernegate := falseif j < len(pat) && (pat[j] == '!' || pat[j] == '^') {negate = truej++ // skip the marker; scan the members after it}// ... scan members as before ...if negate { matched = !matched }