Goで単純な文字列を逆にするにはどうすればよいですか?
33 に答える
Go1 では、ルーンは組み込み型です。
func Reverse(s string) string {
runes := []rune(s)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
golang-nuts メーリング リストの Russ Cox は、次のように提案しています。
package main
import "fmt"
func main() {
input := "The quick brown 狐 jumped over the lazy 犬"
// Get Unicode code points.
n := 0
rune := make([]rune, len(input))
for _, r := range input {
rune[n] = r
n++
}
rune = rune[0:n]
// Reverse
for i := 0; i < n/2; i++ {
rune[i], rune[n-1-i] = rune[n-1-i], rune[i]
}
// Convert back to UTF-8.
output := string(rune)
fmt.Println(output)
}
これは、関数をいじることなく機能します。
func Reverse(s string) (result string) {
for _,v := range s {
result = string(v) + result
}
return
}
Go サンプル プロジェクトから: golang/example/stringutil/reverse.go、Andrew Gerrand 作
/*
Copyright 2014 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Reverse returns its argument string reversed rune-wise left to right.
func Reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
文字列「bròwn」を反転した後、正しい結果は「nẁorb」ではなく「nwòrb」になるはずです。
文字 o の上の墓に注意してください。
「as⃝df̅」などの文字を組み合わせて「f̅ds⃝a」という逆の結果を示す Unicode を保持するには、
以下にリストされている別のコードを参照してください。
これは、次の 2 つのことを考慮して、Unicode 文字列で機能します。
- 範囲は、Unicode 文字を列挙することによって文字列に作用します
- string は、各要素が Unicode 文字である int スライスから構築できます。
だからここに行く:
func reverse(s string) string {
o := make([]int, utf8.RuneCountInString(s));
i := len(o);
for _, c := range s {
i--;
o[i] = c;
}
return string(o);
}
Simonが彼の解決策を投稿したとき、私はこの質問に気付きました。他の提案されたソリューションにも欠陥があります。それらは機能しないか、非効率的です。
文字列が有効な UTF-8 でない場合、または文字列に結合文字が含まれている場合を除いて、これは機能する効率的なソリューションです。
package main
import "fmt"
func Reverse(s string) string {
n := len(s)
runes := make([]rune, n)
for _, rune := range s {
n--
runes[n] = rune
}
return string(runes[n:])
}
func main() {
fmt.Println(Reverse(Reverse("Hello, 世界")))
fmt.Println(Reverse(Reverse("The quick brown 狐 jumped over the lazy 犬")))
}
ここには答えが多すぎます。それらのいくつかは明らかな複製です。しかし、左からでも最適解を選ぶのは難しい。
だから私は答えを調べ、ユニコードで機能しないものを捨て、重複も削除しました。生存者をベンチマークして、最速を見つけました。帰属表示付きの結果は次のとおりです (私が見逃したが追加する価値のある回答に気付いた場合は、ベンチマークを自由に変更してください)。
Benchmark_rmuller-4 100000 19246 ns/op
Benchmark_peterSO-4 50000 28068 ns/op
Benchmark_russ-4 50000 30007 ns/op
Benchmark_ivan-4 50000 33694 ns/op
Benchmark_yazu-4 50000 33372 ns/op
Benchmark_yuku-4 50000 37556 ns/op
Benchmark_simon-4 3000 426201 ns/op
したがって、 rmuller による最速の方法は次のとおりです。
func Reverse(s string) string {
size := len(s)
buf := make([]byte, size)
for start := 0; start < size; {
r, n := utf8.DecodeRuneInString(s[start:])
start += n
utf8.EncodeRune(buf[size-start:], r)
}
return string(buf)
}
何らかの理由でベンチマークを追加できないので、そこからコピーできますPlayGround(そこでテストを実行することはできません)。名前を変更して実行しますgo test -bench=.
//Reverse reverses string using strings.Builder. It's about 3 times faster
//than the one with using a string concatenation
func Reverse(in string) string {
var sb strings.Builder
runes := []rune(in)
for i := len(runes) - 1; 0 <= i; i-- {
sb.WriteRune(runes[i])
}
return sb.String()
}
//Reverse reverses string using string
func Reverse(in string) (out string) {
for _, r := range in {
out = string(r) + out
}
return
}
BenchmarkReverseStringConcatenation-8 1000000 1571 ns/op 176 B/op 29 allocs/op
BenchmarkReverseStringsBuilder-8 3000000 499 ns/op 56 B/op 6 allocs/op
string.Builder を使用すると、文字列連結を使用するよりも約 3 倍高速です
これはまったく異なります。他の回答には記載されていませんが、より機能的なアプローチと言えます。
func reverse(s string) (ret string) {
for _, v := range s {
defer func(r rune) { ret += string(r) }(v)
}
return
}
これは最速の実装です
func Reverse(s string) string {
size := len(s)
buf := make([]byte, size)
for start := 0; start < size; {
r, n := utf8.DecodeRuneInString(s[start:])
start += n
utf8.EncodeRune(buf[size-start:], r)
}
return string(buf)
}
const (
s = "The quick brown 狐 jumped over the lazy 犬"
reverse = "犬 yzal eht revo depmuj 狐 nworb kciuq ehT"
)
func TestReverse(t *testing.T) {
if Reverse(s) != reverse {
t.Error(s)
}
}
func BenchmarkReverse(b *testing.B) {
for i := 0; i < b.N; i++ {
Reverse(s)
}
}
これは確かに最もメモリ効率の高いソリューションではありませんが、「単純な」UTF-8 セーフ ソリューションの場合、次のようにすれば作業が完了し、ルーン文字が壊れることはありません。
私の意見では、このページで最も読みやすく、理解しやすいものです。
func reverseStr(str string) (out string) {
for _, s := range str {
out = string(s) + out
}
return
}
次の 2 つの方法は、合成文字を保持する最速のソリューションよりも高速に実行されますが、ベンチマークの設定に何かが欠けているわけではありません。
//input string s
bs := []byte(s)
var rs string
for len(bs) > 0 {
r, size := utf8.DecodeLastRune(bs)
rs += fmt.Sprintf("%c", r)
bs = bs[:len(bs)-size]
} // rs has reversed string
これに触発された2番目の方法
//input string s
bs := []byte(s)
cs := make([]byte, len(bs))
b1 := 0
for len(bs) > 0 {
r, size := utf8.DecodeLastRune(bs)
d := make([]byte, size)
_ = utf8.EncodeRune(d, r)
b1 += copy(cs[b1:], d)
bs = bs[:len(bs) - size]
} // cs has reversed bytes
注:この回答は 2009 年のものであるため、現在はおそらくより良い解決策が存在します。
少し「回りくどい」ように見え、おそらくあまり効率的ではありませんが、Reader インターフェイスを使用して文字列から読み取る方法を示しています。IntVectors は、utf8 文字列を操作する場合のバッファーとしても非常に適しているようです。
「サイズ」部分を省略し、Insert でベクターに挿入するとさらに短くなりますが、新しいルーンが追加されるたびにベクター全体を 1 つ押し戻す必要があるため、効率が悪いと思います。 .
このソリューションは間違いなく utf8 文字で機能します。
package main
import "container/vector";
import "fmt";
import "utf8";
import "bytes";
import "bufio";
func
main() {
toReverse := "Smørrebrød";
fmt.Println(toReverse);
fmt.Println(reverse(toReverse));
}
func
reverse(str string) string {
size := utf8.RuneCountInString(str);
output := vector.NewIntVector(size);
input := bufio.NewReader(bytes.NewBufferString(str));
for i := 1; i <= size; i++ {
rune, _, _ := input.ReadRune();
output.Set(size - i, rune);
}
return string(output.Data());
}
func Reverse(s string) string {
r := []rune(s)
var output strings.Builder
for i := len(r) - 1; i >= 0; i-- {
output.WriteString(string(r[i]))
}
return output.String()
}
ユニコードで動作すると思うバージョン。utf8.Rune関数に基づいて構築されています。
func Reverse(s string) string {
b := make([]byte, len(s));
for i, j := len(s)-1, 0; i >= 0; i-- {
if utf8.RuneStart(s[i]) {
rune, size := utf8.DecodeRuneInString(s[i:len(s)]);
utf8.EncodeRune(rune, b[j:j+size]);
j += size;
}
}
return string(b);
}
以下のコードを試してください:
package main
import "fmt"
func reverse(s string) string {
chars := []rune(s)
for i, j := 0, len(chars)-1; i < j; i, j = i+1, j-1 {
chars[i], chars[j] = chars[j], chars[i]
}
return string(chars)
}
func main() {
fmt.Printf("%v\n", reverse("abcdefg"))
}
詳細については、http: //golangcookbook.com/chapters/strings/reverse/
およびhttp://www.dotnetperls.com/reverse-string-goを確認してください。
package reverseString
import "strings"
// ReverseString - output the reverse string of a given string s
func ReverseString(s string) string {
strLen := len(s)
// The reverse of a empty string is a empty string
if strLen == 0 {
return s
}
// Same above
if strLen == 1 {
return s
}
// Convert s into unicode points
r := []rune(s)
// Last index
rLen := len(r) - 1
// String new home
rev := []string{}
for i := rLen; i >= 0; i-- {
rev = append(rev, string(r[i]))
}
return strings.Join(rev, "")
}
Test
package reverseString
import (
"fmt"
"strings"
"testing"
)
func TestReverseString(t *testing.T) {
s := "GO je úžasné!"
r := ReverseString(s)
fmt.Printf("Input: %s\nOutput: %s", s, r)
revR := ReverseString(r)
if strings.Compare(s, revR) != 0 {
t.Errorf("Expecting: %s\n. Got: %s\n", s, revR)
}
}
Output
Input: GO je úžasné!
Output: !énsažú ej OG
PASS
ok github.com/alesr/reverse-string 0.098s
func reverseStr(b string) {
for _, v := range []rune(b) {
defer fmt.Printf("%c", v)
}
}
Defer は LIFO - Last in First Out であるため、これに役立ちます。