small medium large xlarge

Dave_gnome_head_isolated_pragsmall
16 Jul 2013, 02:16
Dave Thomas (370 posts)
  • Write a function to capitalize the sentences in a string. Each sentence is terminated by a period and a space. Right now, the case of the characters in the string is random.

    iex> capitalize_sentences("oh. a DOG. woof. ")
    "Oh. A dog. Woof. "
    

A Possible Solution</summary>

defmodule MyString do

  def capitalize_sentences(string) do
    string
    |> String.split(%r{\.\s+})
    |> Enum.map(String.capitalize(&1))
    |> Enum.join(". ")
  end

end

IO.inspect MyString.capitalize_sentences("oh. a DOG. woof. ") 

</details>

Generic-user-small
07 Jan 2014, 00:59
Eric Liaw (3 posts)

irc chat discussion noted a fix for this should have a & in front of the String.capitalize, so it would instead be:

  def capitalize_sentences(string) do
    string
    |> String.split(%r{\.\s+})
    |> Enum.map(&String.capitalize(&1))
    |> Enum.join(". ")
  end
Generic-user-small
21 Jun 2014, 01:35
Luke Imhoff (6 posts)

You can get rid of the argument to Enum.join with a slightly more complex regex as I used in my solution:

defmodule Sentences do
  def captialize_sentences(string) do
    String.split(string, ~r{(?<=\. )(?=.)})
    |> Enum.map(&String.capitalize/1)
    |> Enum.join
  end
end

The regex does a look behind (?<=) for \. and then I had to add a look ahead (?=) for any character ., so that I didn’t get an empty final string after “woof. “.

Generic-user-small
12 Nov 2014, 17:53
Elliot Finley (13 posts)

Here is my version:

defmodule MyString do
  def capitalize_sentences(string) do
    string
    |> String.split(~r{\.\s+}, trim: true)
    |> Enum.map(&String.capitalize/1)
    |> Enum.join(". ")
    |> add_period
  end

  defp add_period(string) do string <> "." end
end
9863_pragsmall
05 Dec 2014, 21:15
Suraj Kurapati (12 posts)

I thought this exercise was about pattern matching on binaries, not about regular expressions:

defmodule MyString do
  def capitalize_sentences(string, starting\\true)
  def capitalize_sentences(<< ".", " ", tail::binary >>, _starting) do
    ". " <> capitalize_sentences(tail, true)
  end
  def capitalize_sentences(<< head::utf8, tail::binary >>, true) do
    String.upcase(<< head >>) <> capitalize_sentences(tail, false)
  end
  def capitalize_sentences(<< head::utf8, tail::binary >>, false) do
    String.downcase(<< head >>) <> capitalize_sentences(tail, false)
  end
  def capitalize_sentences(empty=<< >>, _starting), do: empty
end

The sample solution doesn’t seem to reflect the spirit of this excerise, which happens to be under the “Binaries and Pattern Matching” section of Chapter 11 in the P1.0 printing of this book. :-/

Generic-user-small
29 Dec 2014, 22:07
Pierre Sugar (56 posts)
defmodule MyString

  def capitalize(sentences), 
    do: capitalize_sentences(String.capitalize(sentences))
  def capitalize_sentences(<<". ", tail::binary>>), 
    do: <<". ">> <> capitalize_sentences(String.capitalize(tail))
  def capitalize_sentences(<<head::utf8, tail::binary>>), 
    do: <<head>>  <> capitalize_sentences(tail)
  def capitalize_sentences(<<>>), do: ""
    
end
Generic-user-small
24 Nov 2015, 09:43
Pravin Dahal (4 posts)

I agree with Suraj. Other solutions make use of regex, which do not reflect the spirit of the exercise.

Here is my solution:

defmodule Exercise
        def _capitalize(<<head :: utf8, <<>> >>, _, _) do
                <<head>>
        end
        def _capitalize(<<>>, _, _), do: <<>>
        def _capitalize(<< head :: utf8, tail :: binary >>, ".", " ") do
                String.upcase(<< head >>) <> _capitalize(tail, " ", << head >>)
        end
        def _capitalize(<< head :: utf8, tail :: binary >>, _, prev2) do
                String.downcase(<< head >>) <> _capitalize(tail, prev2, << head >>)
        end
        def capitalize(str), do: _capitalize(str, ".", " ")
end
Generic-user-small
14 Feb 2016, 06:59
Gerry Shaw (3 posts)

Here is another solution using next_codepoint method to iterate over the code points in the string (vs regex).


def capitalize_sentences(str), do: _capitalize_sentences(String.next_codepoint(str), true)
def _capitalize_sentences(nil, _capitalize_next), do: <<>>
def _capitalize_sentences({codepoint, rest}, capitalize_next) do
  if codepoint != " " do
    if capitalize_next do
      codepoint = String.upcase(codepoint)
      capitalize_next = false
    else
      codepoint = String.downcase(codepoint)
    end
    if codepoint == "." do
      capitalize_next = true
    end
  end

  codepoint <> _capitalize_sentences(String.next_codepoint(rest), capitalize_next)
end
Generic-user-small
20 Mar 2016, 10:56
Shane Burnham (2 posts)

I once again made it slightly more difficult than I needed to trying to get rid of white space.


defmodule StringTime do
  def capitalize_sentences(string) do
    String.strip(string)
    |> String.split(".")
    |> Enum.map(fn(x) -> String.strip(x) end)
    |> Enum.map(fn(x) -> String.capitalize(x) end)
    |> Enum.join(". ")
    |> String.strip()
    |> IO.puts()
  end
end

Generic-user-small
27 Mar 2016, 19:24
Nathan Hessler (10 posts)

I stuck with the recursive examples before this exercise. I’m not happy with my current solution. specifically around with how I’m building the result. feels wrong to break the string down into code points then manually convert them back to strings to capitalize or downcase.

defmodule MyString do

  def capitalize_sentences(string), do: _capitalize_sentences(string, "", true)

  defp _capitalize_sentences(<<>>, result, _capitalize), do: result
  defp _capitalize_sentences(<< ". ",  tail :: binary >> , result, _capitalize) do
    _capitalize_sentences(tail, "#{result}. ", true)
  end
  defp _capitalize_sentences(<< " ", tail :: binary >>, result, capitalize) do
    _capitalize_sentences(tail, "#{result} ", capitalize)
  end
  defp _capitalize_sentences(<< head :: utf8, tail :: binary >>, result, false) do
    _capitalize_sentences(tail, "#{result}#{String.downcase(List.to_string([head]))}", false)
  end
  dep _capitalize_sentences(<< head :: utf8, tail :: binary >>, result, true) do
    _capitalize_sentences(tail, "#{result}#{String.capitalize(List.to_string([head]))}", false)
  end

end

Generic-user-small
06 May 2016, 00:34
Sam (6 posts)

It works, but stuck in the old ways - got to learn functional composition soon.


def capitalize_sentences(s) do
    _capitalize(s, true, "")
  end

  defp _capitalize(<<>>, cap?, output_str) do
    output_str
  end

  defp _capitalize(<< h :: utf8, t :: binary >>, cap?, output_str) when h == ?. do
    _capitalize(t, true, output_str <> ".")
  end

  defp _capitalize(<< h :: utf8, t :: binary >>, cap?, output_str) when h == ?\s do
    _capitalize(t, cap?, output_str <> " ")
  end

  defp _capitalize(<< h :: utf8, t :: binary >>, cap?, output_str) when cap? == true do
    _capitalize(t, false, output_str <> String.capitalize("" <> <<h>> ))
  end

  defp _capitalize(<< h :: utf8, t :: binary >>, cap?, output_str) do
    _capitalize(t, false, output_str <> String.downcase("" <> <<h>> ))
  end

Like the terseness of Dave’s solution. However, note that the reg-ex should use a ~ and not %

"ab. c" |> String.split(%r{\.\s+})
** (SyntaxError) iex:3: unexpected token: "\" (column 26, codepoint U+005C)
"ab. c" |> String.split(~r{\.\s+})
["ab", "c"]
Avatar_pragsmall
23 May 2016, 20:36
Dmitriy Nesteryuk (2 posts)

Here is my solution. Maybe I start abusing recursion and it is time to look towards iterators. But, at least I played with the pattern matching ;)

defmodule MyList do
  def capitalize_sentence(sentence) do
    _capitalize_sentence(sentence, true)
  end

  defp _capitalize_sentence(<< ". " :: utf8, tail :: binary >>, _) do
    << ". " :: utf8, _capitalize_sentence(tail, true) :: binary >>
  end

  defp _capitalize_sentence(<< letter :: utf8, tail :: binary >>, true) do
    << (letter - 32) :: utf8, _capitalize_sentence(tail, false) :: binary >>
  end

  defp _capitalize_sentence(<< letter :: utf8, tail :: binary >>, false) when letter in ?A..?Z do
    << (letter + 32) :: utf8, _capitalize_sentence(tail, false) :: binary >>
  end

  defp _capitalize_sentence(<< letter :: utf8, tail :: binary >>, _) do
    << letter :: utf8, _capitalize_sentence(tail, false) :: binary >>
  end

  defp _capitalize_sentence(<<>>, _), do: ""
end
Img_2196_pragsmall
26 May 2016, 21:23
Diogo Neves (12 posts)

Suraj, really like the way you selected beginning of sentences :) I ended up with a similar logic but made the function name explicit

defmodule MyString do
  def capitalize_sentences(<<>>), do: <<>>
  def capitalize_sentences(str), do: _new_sentence(str)

  defp _new_sentence(<< head::utf8, tail::binary >>) do
    String.upcase(<<head>>) <> _capitalize(tail)
  end

  defp _capitalize(<< ?., ?\s >>) do
    <<?., ?\s>>
  end

  defp _capitalize(<< ?., ?\s, tail::binary >>) do
    <<?., ?\s>> <> _new_sentence(tail)
  end

  defp _capitalize(<< head::utf8, tail::binary >>) do
    String.downcase(<<head>>) <> _capitalize(tail)
  end
end
Generic-user-small
31 May 2016, 19:10
Meinert Schwartau (1 post)

Another solution. I’m not really sure if I like it because I’m having two functions which call each other. But I think it’s more readable than some solutions which use strange parameters to know if they should upcase or downcase. Not so readable than the split / join solution though ;-)

defmodule MyStrings do

    def capitalize_sentences(string), do: upcase_first_char(string)

    defp upcase_first_char(<< " ", tail :: binary >>), do: " " <> upcase_first_char(tail)

    defp upcase_first_char(<< head :: utf8, tail :: binary >>), do: String.upcase(<<head>>) <> downcase_till_point(tail)

    defp upcase_first_char(<<>>), do: ""

    defp downcase_till_point(<< ".", tail :: binary >>), do: "." <> upcase_first_char(tail)

    defp downcase_till_point(<< head :: utf8, tail :: binary >>), do: String.downcase(<<head>>) <> downcase_till_point(tail)

    defp downcase_till_point(<<>>), do: ""

end
Generic-user-small
30 Jun 2016, 21:04
Romario Alejandro López Castillo (4 posts)

My solution

defmodule MyString do
  def capitalize_sentence(sentence) do
     String.split(sentence, ". ")
      |> Enum.map(&String.capitalize(&1))
      |> Enum.join(". ")
  end
end
You must be logged in to comment