s = "héllo"
IO.inspect(s)
IO.inspect(is_binary(s))
"héllo"
true
Strings are UTF-8 encoded binaries, written in double quotes.
s = "héllo"
IO.inspect(s)
IO.inspect(is_binary(s))
"héllo"
true
Length in characters and size in bytes differ as soon as you leave ASCII.
IO.inspect(String.length(s))
IO.inspect(byte_size(s))
5
6
Graphemes are what a reader sees as one character. Some, like flag emoji, are several codepoints.
flag = "🇮🇳"
IO.inspect(String.length(flag))
IO.inspect(String.codepoints(flag))
IO.inspect(byte_size(flag))
1
["🇮", "🇳"]
8
The String module works on graphemes.
IO.inspect(String.upcase(s))
IO.inspect(String.reverse(s))
IO.inspect(String.split("a,b,,c", ","))
IO.inspect(String.split(" many spaces "))
IO.inspect(String.slice("elixir", 1..3))
"HÉLLO"
"olléh"
["a", "b", "", "c"]
["many", "spaces"]
"lix"
Interpolation calls to_string/1 on the value.
n = 42
IO.puts("n is #{n}")
n is 42
Binaries can be pattern matched, which makes parsing prefixes cheap.
"user:" <> id = "user:1234"
IO.inspect(id)
<<first::utf8, rest::binary>> = s
IO.inspect(first)
IO.inspect(rest)
"1234"
104
"éllo"
Single quotes make a charlist: a list of integer
codepoints, mostly for calling Erlang APIs. Modern
Elixir prints them with the ~c sigil.
IO.inspect(~c"abc")
IO.inspect(~c"abc" == [97, 98, 99])
IO.inspect(to_string(~c"abc"))
~c"abc"
true
"abc"
Pitfall:
'abc'is not a string. It's a charlist, and"abc" == 'abc'isfalse. Elixir 1.20 emits a deprecation warning for single-quoted charlists; write~c"abc"when you really mean one.
Pitfall:
String.length/1walks the whole string (O(n)) and counts graphemes. If you need a size limit for storage or the network, you wantbyte_size/1, which is O(1).