5

I have a string like this

var sentence string = "the biggest ocean is the Pacific ocean"

I want to be able to capitalize the first letter t in the input string, so that the string becomes

"The biggest ocean is the Pacific ocean"

How to do that in Go?

I have tried using strings.Title and strings.ToTitle however they don't do what I want.

blackgreen
  • 34,072
  • 23
  • 111
  • 129
Ineedanswers
  • 71
  • 1
  • 4

4 Answers4

5

Assuming that your input string is valid UTF-8, this thread (Golang - ToUpper() on a single byte?) is close enough, though not quite a perfect duplicate. We can build on that to come to an acceptable solution using unicode.ToUpper on the first rune of the string.

    r := []rune(s)
    r[0] = unicode.ToUpper(r[0])
    s := string(r)

Or with a "clever" one-liner:

    s := string(append([]rune{unicode.ToUpper(r[0])}, r[1:]...))

Unlike strings, rune slices are not immutable, so you can replace the first rune with ToUpper, which will take care of non-ASCII and/or multi-byte code points that do have upper cases (e.g. Russian) and leave alone those that don't (e.g. Asian scripts)

NOTE: there is a difference between UPPER case and TITLE case, which is simply explained here. In short, digraph characters like DŽ will have different title case (Dž, only first grapheme capitalized) and upper cases (DŽ, both graphemes capitalized). If you actually need titlecase, use unicode.ToTitle.

NOTE 2: converting to/from string to []rune involves copying, because you get a mutable slice from an immutable string. Do profile your application if you expect to use it in performance-sensitive code.

Playground: https://go.dev/play/p/HpCBM7cRflZ


If you have a sizeable input string where a full rune slice conversion becomes too expensive, you can work around this using a capped strings.SplitN on some separator, essentially to extract the first word of the text and use only that in the conversion:

sep := " "
ss := strings.SplitN(s, sep, 2)

r := []rune(ss[0])
r[0] = unicode.ToUpper(r[0])

s = string(r) + sep + ss[1])

Benchmarking with a ~30K input string shows a significant difference:

go test -v -bench=. -benchmem
goos: darwin
goarch: arm64
pkg: example.com
BenchmarkRuneConv-10            6376        183691 ns/op      258049 B/op          3 allocs/op
BenchmarkSplitN-10           1709989           706.1 ns/op      4152 B/op          3 allocs/op
PASS
ok      example.com 3.477s
blackgreen
  • 34,072
  • 23
  • 111
  • 129
  • The previous code has a problems. For cases like `""` or `" hello"` get a panic. So some extra code is needed `func firstLetterToUppercase(s string) string { sep := " " ss := strings.SplitN(s, sep, 2) r := []rune(ss[0]) if len(r) == 0 { return s } r[0] = unicode.ToUpper(r[0]) s = string(r) if len(ss) > 1 { s += sep + ss[1] } return s }` – Pedro C. Abreu Mar 01 '23 at 18:28
1

The simplest way to achieve the desired result is to use strings.ToUpper() function. Refer

    var input string = "the biggest ocean is the Pacific ocean"
    res := strings.ToUpper(input[:1]) + input[1:]

    fmt.Println(res)

OR

You can try it on goplayground

Ashutosh Singh
  • 721
  • 3
  • 6
-1

Get the first rune, title case that rune and reassemble the string:

sentence := "the biggest ocean is the Pacific ocean"
r, i := utf8.DecodeRuneInString(sentence)
sentence = string(unicode.ToTitle(r)) + sentence[i:]
fmt.Println(sentence)
  • 2
    [utf8.DecodeRuneInString](https://pkg.go.dev/unicode/utf8#DecodeRuneInString) may return `RuneError` for an empty input string (or if the the start of the string has an invalid rune) - so may want to check for that. – colm.anseo Dec 02 '21 at 23:29
-11

I have simple solution for you.

Its a fork I have of someones project on Github

https://github.com/CleanMachine1/capitalise

To use it just run in a terminal:

go mod init MODULENAME
go get github.com/cleanmachine1/capitalise

then in your code you can use


package main

import ("github.com/cleanmachine1/capitalise")

func main(){
 sentence = capitalise.First(sentence)
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
  • 4
    @CleanMachine1 you might have better success quoting the repo code - rather than tying a solution to a third-party package. – colm.anseo Dec 02 '21 at 23:32