# String.downcase/1 can turn garbage into valid input: use :ascii

`String.downcase/1` and `String.upcase/1` follow Unicode case mapping. That's usually what you want for human text, but not for identifiers:

```elixir
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 "ﬁ" 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:

```elixir
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](https://hex.pm/packages/pix_brcode) (Brazilian Pix "copia e cola" payloads).*

---

Created by: igorgbr
Date: October 14, 2026
URL: https://elixirdrops.net/d/cR2BfXbM
