Skip to content

Add String.titlecase/2 #10008

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 40 additions & 2 deletions lib/elixir/lib/string.ex
Original file line number Diff line number Diff line change
Expand Up @@ -859,15 +859,53 @@ defmodule String do
def capitalize(string, mode \\ :default)

def capitalize(<<char, rest::binary>>, :ascii) do
char = if char >= ?a and char <= ?z, do: char - 32, else: char
<<char>> <> downcase(rest, :ascii)
<<capitalize_ascii_char(char)>> <> downcase(rest, :ascii)
end

def capitalize(string, mode) when is_binary(string) do
{char, rest} = String.Casing.titlecase_once(string, mode)
char <> downcase(rest, mode)
end

defp capitalize_ascii_char(char) when char >= ?a and char <= ?z, do: char - 32
defp capitalize_ascii_char(char), do: char

@doc """
Converts only the first character in the given string to
uppercase according to `mode`.

`mode` may be `:default`, `:ascii` or `:greek`. The `:default` mode considers
all non-conditional transformations outlined in the Unicode standard. `:ascii`
lowercases only the letters A to Z. `:greek` includes the context sensitive
mappings found in Greek.

## Examples

iex> String.titlecase("abcd")
"Abcd"

iex> String.titlecase("ABCd")
"ABCd"

iex> String.titlecase("fin")
"Fin"

iex> String.titlecase("olá")
"Olá"

"""
@spec titlecase(t, :default | :ascii | :greek) :: t
def titlecase(string, mode \\ :default)

def titlecase(<<char, rest::binary>>, :ascii) do
<<capitalize_ascii_char(char)>> <> rest
end

def titlecase(string, mode) when is_binary(string) do
{char, rest} = String.Casing.titlecase_once(string, mode)
char <> rest
end

@doc false
@deprecated "Use String.trim_trailing/1 instead"
defdelegate rstrip(binary), to: String.Break, as: :trim_trailing
Expand Down
35 changes: 35 additions & 0 deletions lib/elixir/test/elixir/string_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,41 @@ defmodule StringTest do
assert String.capitalize("aáA", :ascii) == "Aáa"
end

test "titlecase/1" do
assert String.titlecase("") == ""
assert String.titlecase("abc") == "Abc"
assert String.titlecase("ABC") == "ABC"
assert String.titlecase("c b a") == "C b a"
assert String.titlecase("1ABc") == "1ABc"
assert String.titlecase("_aBc1") == "_aBc1"
assert String.titlecase(" aBc1") == " aBc1"
end

test "titlecase/1 with UTF-8" do
assert String.titlecase("àáâ") == "Àáâ"
assert String.titlecase("ÀÁÂ") == "ÀÁÂ"
assert String.titlecase("âáàÕ") == "ÂáàÕ"
assert String.titlecase("ÂÁÀõ") == "ÂÁÀõ"
assert String.titlecase("òóôõö") == "Òóôõö"
assert String.titlecase("ÒÓÔÕÖ") == "ÒÓÔÕÖ"
assert String.titlecase("fin") == "Fin"
end

test "titlecase/2 with ascii" do
assert String.titlecase("àáâ", :ascii) == "àáâ"
assert String.titlecase("aáA", :ascii) == "AáA"
end

test "titlecase/1 with greek final sigma" do
assert String.titlecase("σ") == "Σ"
assert String.titlecase("μΜσΣ") == "ΜΜσΣ"
end

test "titlecase/2 with greek final sigma" do
assert String.titlecase("σ", :greek) == "Σ"
assert String.titlecase("σ ςΠ", :greek) == "Σ ςΠ"
end

test "replace_leading/3" do
assert String.replace_leading("aa abc ", "a", "b") == "bb abc "
assert String.replace_leading("__ abc ", "_", "b") == "bb abc "
Expand Down