Reputation: 91
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.
Upvotes: 7
Views: 10239
Reputation: 45041
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.
The most performant solution (see benchmarks below) is the one suggested by this answer which uses utf8.DecodeRuneInString
although you probably want to use ToUpper
and account for possible errors:
r, size := utf8.DecodeRuneInString(text)
if r == utf8.RuneError {
// handle error
}
s = string(unicode.ToUpper(r)) + text[size:]
Here indexing the string with []
doesn't break the encoding because size
is guaranteed to be a valid offset, according to the rune we just decoded.
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)
ToUpper
vs. ToTitle
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
.
Converting string
to/from []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.
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 — or strings.Cut
since later Go versions — 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, although the best and the second best differ by a small margin (benchmark updated with Go 1.22):
go test -v -bench=. -benchmem
goos: darwin
goarch: arm64
pkg: example.com
BenchmarkRuneConv-10 6730 168665 ns/op 155648 B/op 2 allocs/op
BenchmarkSplitN-10 504634 2357 ns/op 32800 B/op 2 allocs/op
BenchmarkDecodeRune-10 533928 2307 ns/op 32768 B/op 1 allocs/op
PASS
ok example.com 4.981s
With smaller strings, the SplitN
/Cut
solution isn't necessary and utf8.DecodeRuneInString
is the clear winner.
A playground: https://go.dev/play/p/HpCBM7cRflZ
Upvotes: 9
Reputation: 1082
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
Upvotes: 3
Reputation: 7
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)
Upvotes: -1
Reputation: 48
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)
}
Upvotes: -13