We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
String.downcase/1 can turn garbage into valid input: use :ascii
igorgbr
String.downcase/1 and String.upcase/1 follow Unicode case mapping. That’s usually what you want for human text, but not for identifiers:
String.downcase("\u212Aey@example.com")
#=> "key@example.com" # U+212A is the KELVIN SIGN, not the letter K
String.upcase("12ßc")
#=> "12SSC" # 4 characters in, 5 out
String.upcase("\uFB01")
#=> "FI" # the "fi" ligature becomes two letters
If you lowercase an e-mail, a document number or a code before validating it, a string that should be rejected becomes a different, valid value. Your regex never sees the original characters.
Pass :ascii so only A–Z/a–z are mapped and everything else is left untouched:
String.downcase("Fulano@Example.COM", :ascii)
#=> "fulano@example.com"
String.downcase("\u212Aey@example.com", :ascii)
#=> "\u212Aey@example.com" # Kelvin sign kept, so your ASCII regex rejects it
String.upcase("12ßc", :ascii)
#=> "12ßC" # length preserved, ß still there to be rejected
Rule of thumb: if the target format is ASCII, normalize as ASCII.
Found by an independent review while hardening the Pix key parsing in pix_brcode (Brazilian Pix “copia e cola” payloads).
copied to clipboard