web-dev-qa-db-ja.com

Goで文字列を逆にする方法は?

Goで単純な文字列を反転するにはどうすればよいですか?

88
user211499

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)
}
78
yazu

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)
}
51
user181548

これは、機能についていじくり回すことなく機能します。

func Reverse(s string) (result string) {
  for _,v := range s {
    result = string(v) + result
  }
  return 
}
21
Simon

これは、2つのことを考慮して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);
}
14

From 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を保持するには、
以下にリストされている別のコードを参照してください。

http://rosettacode.org/wiki/Reverse_a_string#Go

13
Ivan Chau

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 犬")))
}
11
peterSO

ここには答えが多すぎます。それらのいくつかは明らかに重複しています。しかし、左からでも最適なソリューションを選択することは困難です。

そこで答えを調べて、Unicodeで動作しないものを捨て、重複も削除しました。生存者のベンチマークを行い、最速を見つけました。したがって、ここに属性付きの結果があります(私が見逃したが、追加する価値がある答えに気付いた場合は、ベンチマークを自由に変更してください):

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=.を実行します

6
Salvador Dali

UTF8エンコーディングと結合文字を尊重する次のReverse関数を作成しました。

// Reverse reverses the input while respecting UTF8 encoding and combined characters
func Reverse(text string) string {
    textRunes := []rune(text)
    textRunesLength := len(textRunes)
    if textRunesLength <= 1 {
        return text
    }

    i, j := 0, 0
    for i < textRunesLength && j < textRunesLength {
        j = i + 1
        for j < textRunesLength && isMark(textRunes[j]) {
            j++
        }

        if isMark(textRunes[j-1]) {
            // Reverses Combined Characters
            reverse(textRunes[i:j], j-i)
        } 

        i = j
    }

    // Reverses the entire array
    reverse(textRunes, textRunesLength)

    return string(textRunes)
}

func reverse(runes []rune, length int) {
    for i, j := 0, length-1; i < length/2; i, j = i+1, j-1 {
        runes[i], runes[j] = runes[j], runes[i]
    }
}

// isMark determines whether the rune is a marker
func isMark(r rune) bool {
    return unicode.Is(unicode.Mn, r) || unicode.Is(unicode.Me, r) || unicode.Is(unicode.Mc, r)
}

できる限り効率的で読みやすいものにするために最善を尽くしました。アイデアはシンプルで、ルーンを通過して結合文字を探し、次に結合文字のルーンを元に戻します。すべてをカバーしたら、インプレースで文字列全体のルーン文字を反転します。

この文字列bròwnを逆にします。 òは、2つのルーン文字で表されます。1つはo用で、もう1つは「墓」を表すこのUnicode \u0301a用です。

簡単にするために、このbro'wnのような文字列を表現しましょう。最初に行うことは、結合された文字を探し、それらを逆にすることです。これで、文字列br'ownができました。最後に、文字列全体を反転し、nwo'rbになります。これはnwòrbとして返されます

ここで見つけることができます https://github.com/shomali11/util 使用したい場合。

いくつかの異なるシナリオを示すためのテストケースを次に示します。

func TestReverse(t *testing.T) {
    assert.Equal(t, Reverse(""), "")
    assert.Equal(t, Reverse("X"), "X")
    assert.Equal(t, Reverse("b\u0301"), "b\u0301")
    assert.Equal(t, Reverse("????⚽"), "⚽????")
    assert.Equal(t, Reverse("Les Mise\u0301rables"), "selbare\u0301siM seL")
    assert.Equal(t, Reverse("ab\u0301cde"), "edcb\u0301a")
    assert.Equal(t, Reverse("This `\xc5` is an invalid UTF8 character"), "retcarahc 8FTU dilavni na si `�` sihT")
    assert.Equal(t, Reverse("The quick bròwn 狐 jumped over the lazy 犬"), "犬 yzal eht revo depmuj 狐 nwòrb kciuq ehT")
}
5
Raed Shomali

Stephan202の元の提案に基づいて構築されており、Unicode文字列に対して機能するようです。

import "strings";

func Reverse( orig string ) string {
    var c []string = strings.Split( orig, "", 0 );

    for i, j := 0, len(c)-1; i < j; i, j = i+1, j-1 {
        c[i], c[j] = c[j], c[i]
    }

    return strings.Join( c, "" );
}

文字列パッケージを使用せず、「ユニコードセーフ」ではない代替:

func Reverse( s string ) string {
    b := make([]byte, len(s));
    var j int = len(s) - 1;
    for i := 0; i <= j; i++ {
        b[j-i] = s[i]
    }

    return string ( b );
}
3
martin clayton

書記素クラスタを処理する必要がある場合は、unicodeまたはregexpモジュールを使用してください。

package main

import (
  "unicode"
  "regexp"
)

func main() {
    str := "\u0308" + "a\u0308" + "o\u0308" + "u\u0308"
    println("u\u0308" + "o\u0308" + "a\u0308" + "\u0308" == ReverseGrapheme(str))
    println("u\u0308" + "o\u0308" + "a\u0308" + "\u0308" == ReverseGrapheme2(str))
}

func ReverseGrapheme(str string) string {

  buf := []rune("")
  checked := false
  index := 0
  ret := "" 

    for _, c := range str {

        if !unicode.Is(unicode.M, c) {

            if len(buf) > 0 {
                ret = string(buf) + ret
            }

            buf = buf[:0]
            buf = append(buf, c)

            if checked == false {
                checked = true
            }

        } else if checked == false {
            ret = string(append([]rune(""), c)) + ret
        } else {
            buf = append(buf, c)
        }

        index += 1
    }

    return string(buf) + ret
}

func ReverseGrapheme2(str string) string {
    re := regexp.MustCompile("\\PM\\pM*|.")
    slice := re.FindAllString(str, -1)
    length := len(slice)
    ret := ""

    for i := 0; i < length; i += 1 {
        ret += slice[length-1-i]
    }

    return ret
}
2
masakielastic

既存の実装をインポートすることもできます。

import "4d63.com/strrev"

次に:

strrev.Reverse("abåd") // returns "dåba"

または、文字を結合するユニコードを含む文字列を反転するには:

strrev.ReverseCombining("abc\u0301\u031dd") // returns "d\u0301\u031dcba"

これらの実装は、ユニコードマルチバイトの正しい順序付けと、逆の場合の文字の結合をサポートします。

注:多くのプログラミング言語の組み込み文字列反転関数は結合を保持しません。結合文字を識別するには、実行時間が大幅に長くなります。

2
Leigh McCulloch

このコードは、結合文字のシーケンスをそのまま保持し、無効なUTF-8入力でも機能するはずです。

package stringutil
import "code.google.com/p/go.text/unicode/norm"

func Reverse(s string) string {
    bound := make([]int, 0, len(s) + 1)

    var iter norm.Iter
    iter.InitString(norm.NFD, s)
    bound = append(bound, 0)
    for !iter.Done() {
        iter.Next()
        bound = append(bound, iter.Pos())
    }
    bound = append(bound, len(s))
    out := make([]byte, 0, len(s))
    for i := len(bound) - 2; i >= 0; i-- {
        out = append(out, s[bound[i]:bound[i+1]]...)
    }
    return string(out)
}

Unicode/normプリミティブが割り当てを行わずに文字列の境界を反復処理できる場合、それはもう少し効率的です。 https://code.google.com/p/go/issues/detail?id=9055 も参照してください。

2
rog

これは最速の実装です

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)
    }
}
2
rmuller

ここはまったく異なりますが、他の答えの中でリストされていない、より機能的なアプローチと言えます:

func reverse(s string) (ret string) {
    for _, v := range s {
        defer func(r rune) { ret += string(r) }(v)
    }
    return
}

クレジット

2
Vladimir Bauer

次の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

this に触発された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
1
Sridhar

注:この回答は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());
}
1
Oliver Mason

ルーンはタイプなので、使用します。さらに、Goはセミコロンを使用しません。

func reverse(s string) string {
    l := len(s)
    m := make([]rune, l)

    for _, c := range s {
        l--
        m[l] = c
    }
    return string(m)
}

func main() {
    str := "the quick brown 狐 jumped over the lazy 犬"
    fmt.Printf("reverse(%s): [%s]\n", str, reverse(str))
}
1
Walter

確かに最もメモリ効率のよいソリューションではありませんが、「単純な」UTF-8の安全なソリューションの場合、次の方法でジョブが完了し、ルーン文字を壊しません。

私の意見では、このページで最も読みやすく理解しやすいものです。

func reverseStr(str string) (out string) {
    for _, s := range str {
        out = string(s) + out
    }

    return
}
1
donatJ
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, "")
}

テスト

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)
    }
}

出力

Input: GO je úžasné!
Output: !énsažú ej OG
PASS
ok      github.com/alesr/reverse-string 0.098s
0

単純な文字列の場合、次のような構造を使用できます。

func Reverse(str string) string {
    if str != "" {
        return Reverse(str[1:]) + str[:1]
    }
    return ""   
}
0
Sergo Kurbanov

さらに別のソリューション(tm):

package main 
import "fmt"

type Runes []rune

func (s Runes) Reverse() (cp Runes) {
    l := len(s); cp = make(Runes, l)
    // i <= 1/2 otherwise it will mess up with odd length strings
    for i := 0; i <= l/2; i++ { 
        cp[i], cp[l-1-i] = s[l-1-i], s[i] 
    }
    return cp
}

func (s Runes) String() string {
    return string(s)
}

func main() { 
    input := "The quick brown 狐 jumped over the lazy 犬 +odd" 
    r := Runes(input)
    output := r.Reverse()
    valid := string(output.Reverse()) == input
    fmt.Println(len(r), len(output), r, output.Reverse(), valid)
}
0
OneOfOne
    func reverseString(someString string) string {
        runeString := []rune(someString)
        var reverseString string
        for i := len(runeString)-1; i >= 0; i -- {
            reverseString += string(runeString[i])
        }
        return reverseString
    }
0
saurabh

以下のコードを試してください:

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/
and http://www.dotnetperls.com/reverse-string-go

0
Vishal Solanki

さらに別のソリューションを次に示します。

func ReverseStr(s string) string {
    chars := []rune(s)
    rev := make([]rune, 0, len(chars))
    for i := len(chars) - 1; i >= 0; i-- {
        rev = append(rev, chars[i])
    }
    return string(rev)
}

ただし、上記のyazuのソリューションは、[]rune所定の位置にスライスします。

0
Jabba

私がユニコードで動作すると思うバージョン。 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);
}
0
Jonathan Wright