mikl

mikl

String.capitalize() should have a “leave the rest of the word alone” option

I wanted to capitalize a string, and tried using String.capitalize().

That generally works well, until you try to capitalize a word like ATM, which then comes out as Atm.

That is correct according to the documentation, as it states that String.capitalize() does this:

Converts the first character in the given string to uppercase and the remainder to lowercase according to mode. [emphasis mine]

Now that is not what I expected from a function called capitalize(). I naïvely thought that would only touch the first letter, as String.capitalize does in Python and similarly named functions does in other programming languages.

Elixir is probably mimicking Ruby here, and the point of this post is not to say that the implementation is wrong, it’s too late to change now anyway.

However, it would be handy if there was a :first_letter_only or similar mode, that would only touch the first letter, so developers everywhere won’t have to write their own capitalize function to be able to safely capitalize words without mangling abbreviations.

(If you come across this topic wanting to just capitalize the first letter, you can use String.Casing.titlecase_once(word, nil), although this is a little undocumented). Don’t do this, see comment from josevalim below.

Most Liked

mikl

mikl

Since this is a fairly common thing to do, and one with a bunch of tricky edge cases, wouldn’t it be the kind of thing that belongs in the standard library?

At least as a relative newcomer to Elixir, I find it a bit surprising to have to write my own String.cap_first() implementation, because the language does not provide one.

Anyway, Erlang’s titlecase() (added in OTP 20) function works for my use case at least, it can be called like this :string.titlecase(text) – although you should probably have a wrapper for it to filter out non-binary strings and such things.

josevalim

josevalim

Creator of Elixir

The reason why we do first letter only is because Unicode has specific rules that consider the rest is being lowercased.

For the behaviour that you want, you should be able to implement it using String.next_grapheme, getting the first part, upcasing it an then concatenating the rest. Just make sure to take into account empty strings.

Don’t do this. :slight_smile: String.Casing is private API and may change at any time, breaking your code.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Nice! No point in slicing twice though:

    <<first_grapheme::utf8, rest::binary>> = string
    String.capitalize(<<first_grapheme::utf8>>) <> rest

EDIT: Fixed a bug pointed out by @adamu thanks!

Where Next?

Popular in Discussions Top

matthias_toepp
I’d love to hear what people think about Wisp, the new Gleam web framework started by Gleam’s primary creator Louis Pilfold. Gleam, alon...
New
WildYorkies
It seems that the more I read, the more I find Elixir users speaking about all the ways that Elixir is not good for x, y, and z use cases...
New
AstonJ
If a newbie asked you about Phoenix Contexts, how would you explain the basics to them? Feel free to be as concise or in-depth as you li...
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31307 143
New
AstonJ
Are there any Elixir or Erlang libraries that help with this? I’ve been thinking how streaming services like twitch have exploded recentl...
New
CharlesO
Erlang :list.nth simple, but 1 - based nth(1, [H|_]) -&gt; H; nth(N, [_|T]) when N &gt; 1 -&gt; nth(N - 1, T). Elixir Enum.at … coo...
New
New
AstonJ
Can you believe the first professionally published Elixir book was published just 8 years ago? Since then I think we’ve seen more books f...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
kostonstyle
Hi all How can I compare haskell with elixir, included tools, webservices, ect. Thanks
New

Other popular topics Top

hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a &gt; b) do {:ok, "a"} end if (a &lt; b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43806 214
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" =&gt; #BSON.ObjectId&lt;58eb1a7a9ad169198c3dXXXX&gt;, "email" =&gt; ...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement