Làm thế nào để đảo ngược một chuỗi trong Go?


102

Làm thế nào chúng ta có thể đảo ngược một chuỗi đơn giản trong cờ vây?


1
Theo như tôi hiểu, các giải pháp được đưa ra bên dưới không hoạt động với các ký tự được tạo sẵn hoặc kết hợp, như cho a+´thay vì cho á. Tôi tự hỏi làm thế nào điều đó có thể được tính đến, mà không cần bình thường hóa nó.
siritinga

Nếu bạn bối rối với một số lượng lớn các câu trả lời tương tự, hãy kiểm tra điểm chuẩn của tôi .
Salvador Dali,

Câu trả lời:


94

Trong Go1 rune là một loại nội trang.

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

4
bạn không thể sử dụng len () trong Go để tìm độ dài của một chuỗi / Array / Slice, v.v. Đây là lý do tại sao? - len () trong Go có nghĩa là kích thước của đầu vào tính bằng byte. Nó không tương ứng với chiều dài của nó. - Không phải tất cả rune của utf8 đều có cùng kích thước. Nó có thể là 1, 2, 4 hoặc 8. - Bạn nên sử dụng phương thức RuneCountInString của gói unicode / ut8 để lấy độ dài của rune.
Anvesh Checka

15
@AnveshChecka, điều đó không chính xác. Xem golang.org/pkg/builtin/#len - len () trên một lát chắc chắn trả về số phần tử chứ không phải kích thước tính bằng byte. Một lát rune là cách chính xác để làm điều đó.
chowey

3
@ рытфолд Điều này không hoạt động với việc kết hợp các ký tự. Xem play.golang.org/p/sBgZAV7gCb , ký tự kết hợp không được hoán đổi với cơ sở của nó.
chowey

53

Russ Cox, trong danh sách gửi thư golang-nut , gợi ý

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

20
Tôi thích cách họ buộc bạn phải suy nghĩ về các mã hóa.
György Andrasek

9
lạc đề: tại sao lại là [golang-nut] mà không phải [go-nut]?
Jimmy

2
Chà, wtf có bị gán kép khi đảo ngược không? Hấp dẫn. Bây giờ, hãy nghĩ về một chuỗi có số rune không đồng đều. Tuy nhiên, phần giữa được đối xử đặc biệt, với kết quả cuối cùng chính xác. :) Một tối ưu hóa nhỏ thú vị mà tôi sẽ không nghĩ đến ngay lập tức.
Kissaki

4
Tôi không hiểu tại sao chuyển đổi này sang rune, tại sao không rune:=[]rune(input)?
siritinga

1
Bạn không cần vòng lặp for range đầu tiên. đầu ra: = [] rune (đầu vào); n: = len (output) Và bạn không cần rune = rune [0: n]
dvallejo

29

Điều này hoạt động mà không cần tất cả các chức năng:

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

6
Trong khi nó hoạt động, vì các chuỗi là bất biến, nó rất kém hiệu quả. Tôi đã đăng một giải pháp hiệu quả hơn.
peterSO

5
Đây là nhiều quá dễ hiểu. Làm cho nó khó hơn :-) (và, "cộng thêm một" để bắt đầu với nó)
Roboprog

2
Đây là câu trả lời tốt nhất trừ khi đảo ngược chuỗi là nút cổ chai của bạn.
Banjocat

1
@dolmen - tại sao điều này không xử lý việc kết hợp các ký tự? một phạm vi trên một chuỗi trả về một rune là một điểm mã.
Stan R.

1
@StanR. Rune không phải là glyph. Một glyph có thể được tạo từ nhiều codepoints / rune. Xem reedbeta.com/blog/programmers-intro-to-unicode/#comosystem-marks Đảo ngược codepoints sẽ gắn các điểm kết hợp vào một điểm mã cơ sở khác.
dolmen

14

Điều này hoạt động trên chuỗi unicode bằng cách xem xét 2 điều:

  • phạm vi hoạt động trên chuỗi bằng cách liệt kê các ký tự unicode
  • chuỗi có thể được xây dựng từ các lát int trong đó mỗi phần tử là một ký tự unicode.

Vì vậy, ở đây nó đi:

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

Tôi sẽ gán i:=len(o)-1và sau đó gấp for thành một dòng for _, c:=range s { o[i--]=c; }. Man I HATE the for mà không có dấu ngoặc đơn - điều này có được phép không:for(_, c:=range s) { o[i--]=c; }
Lawrence Dol

Bạn có thể giải thích những gì _ làm?
Lawrence Dol,

6
@Software_Monkey: o [i--] = c không được phép trong Go. - và ++ là các câu lệnh, không phải là biểu thức. _ nghĩa là loại bỏ (bỏ qua) biến đó.
Randy Sugianto 'Yuku'

1
với đi 1.1+ nó sẽ trả về lỗi trong chuỗi ([] int) dòng, nếu thay vì [] rune loại được sử dụng làm nước giải khát, tất cả các công trình
Otuk

1
@yuku: Vẫn không thành công trên s: = "Les Mise \ u0301rables"
Stefan Steiger

13

Dự án ví dụ từ Go: golang / example / stringutil / reverse.go , bởi 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)
}

Go Playground để đảo ngược một chuỗi

Sau khi đảo ngược chuỗi "bròwn", kết quả đúng phải là "nwòrb", không phải "nẁorb".
Lưu ý phần mộ phía trên chữ o.


Để bảo toàn Unicode kết hợp các ký tự như "as⃝df̅" với kết quả ngược lại "f̅ds⃝a",
vui lòng tham khảo một mã khác được liệt kê bên dưới:

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


2
Cảm ơn bạn đã làm rõ sự khác biệt từ stackoverflow.com/a/10030772/3093387 - có vẻ như hai giải pháp này khác nhau về cách chúng xử lý các chuỗi như "bròwn".
josliber

Cảm ơn đề cập đến các giải pháp Rosettacode rằng xử lý kết hợp ký tự
Dolmen

11

Tôi nhận thấy câu hỏi này khi Simon đăng giải pháp của anh ấy , vì các chuỗi là bất biến, rất kém hiệu quả. Các giải pháp đề xuất khác cũng còn nhiều thiếu sót; chúng không hoạt động hoặc chúng không hiệu quả.

Đây là một giải pháp hiệu quả hoạt động, ngoại trừ khi chuỗi không phải là UTF-8 hợp lệ hoặc chuỗi chứa các ký tự kết hợp.

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

1
chuỗi trả về (rune) Cũng hoạt động.

3
@Tommy: Không, return string(runes)không hoạt động cho mọi trường hợp.
peterSO

bạn có thể vui lòng giải thích thêm một chút về lý do tại sao như vậy không? Tôi đã tạo một chương trình ngắn và nó hoạt động ở đó, nhưng có thể những trường hợp bạn nói đến không được kích hoạt ở đó? play.golang.org/p/yk1sAwFjol

1
@Tommy: Chương trình ngắn của bạn chỉ chứng minh rằng ký tự NUL là một NOP khi được gửi đến máy in hoặc thiết bị đầu cuối. Chức năng Reverse2 của bạn không thành công đối với các chuỗi được mã hóa không phải ASCII UTF-8. Tôi đã sửa đổi chương trình ngắn của bạn để nó là một bài kiểm tra hợp lệ: play.golang.org/p/Ic5G5QEO93
peterSO

Thêm một "giải pháp" sai không xử lý việc kết hợp các ký tự đúng cách.
dolmen

9

Có quá nhiều câu trả lời ở đây. Một số trong số chúng là bản sao rõ ràng. Nhưng ngay cả từ bên trái, thật khó để chọn ra giải pháp tốt nhất.

Vì vậy, tôi đã xem qua các câu trả lời, loại bỏ một trong những không hoạt động cho unicode và cũng loại bỏ các bản sao. Tôi chuẩn những người sống sót để tìm ra người nhanh nhất. Vì vậy, đây là kết quả với sự phân bổ (nếu bạn nhận thấy câu trả lời mà tôi đã bỏ lỡ, nhưng đáng để thêm vào, vui lòng sửa đổi điểm chuẩn):

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

Vì vậy, đây là phương pháp nhanh nhất bằng 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)
}

Vì một số lý do, tôi không thể thêm điểm chuẩn, vì vậy bạn có thể sao chép nó từ PlayGround(bạn không thể chạy thử nghiệm ở đó). Đổi tên nó và chạygo test -bench=.


Không có "giải pháp" nào xử lý việc kết hợp các dấu một cách chính xác.
dolmen

6

Tôi đã viết Reversehàm sau tuân theo mã hóa UTF8 và các ký tự kết hợp:

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

Tôi đã cố gắng hết sức để làm cho nó hiệu quả và dễ đọc nhất có thể. Ý tưởng rất đơn giản, lướt qua các chữ rune để tìm kiếm các ký tự kết hợp sau đó đảo ngược các chữ cái được kết hợp tại chỗ. Khi chúng ta đã bao phủ tất cả, hãy đảo ngược các chữ rune của toàn bộ chuỗi cũng tại chỗ.

Giả sử chúng tôi muốn đảo ngược chuỗi này bròwn. Dấu òđược đại diện bởi hai rune, một cho ovà một cho unicode này \u0301ađại diện cho "mộ".

Để đơn giản, hãy biểu diễn chuỗi như thế này bro'wn. Điều đầu tiên chúng tôi làm là tìm kiếm các ký tự kết hợp và đảo ngược chúng. Vì vậy, bây giờ chúng ta có chuỗi br'own. Cuối cùng, chúng tôi đảo ngược toàn bộ chuỗi và kết thúc bằng nwo'rb. Điều này được trả lại cho chúng tôi nhưnwòrb

Bạn có thể tìm thấy nó ở đây https://github.com/shomali11/util nếu bạn muốn sử dụng nó.

Dưới đây là một số trường hợp thử nghiệm để hiển thị một số trường hợp khác nhau:

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

3

Xây dựng dựa trên đề xuất ban đầu của Stephan202 và dường như hoạt động đối với các chuỗi 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, "" );
}

Thay thế, không sử dụng gói chuỗi, nhưng không phải 'unicode-safe':

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

+1. Điều đó hoạt động. Nhưng tôi phải nói rằng nó là khá kỳ lạ (bây giờ) mà tách và tham gia là cần thiết cho một nhiệm vụ đơn giản như vậy ...
Stephan202

@martin: xin lỗi vì chỉnh sửa đó. Tôi vô tình dán câu trả lời cập nhật của tôi trong câu hỏi của bạn ... tôi rất xấu hổ .
Stephan202

@Stephan - không vấn đề gì. Tôi đã thêm một giải pháp thay thế, dựa trên hàm Bytes gói chuỗi.
martin clayton

@Nosradena: Tôi cuộn lại trong phút cùng (Tôi đã rất ngạc nhiên khi thấy rằng Martin cập nhật câu trả lời của mình với chính xác cùng một văn bản tôi vừa viết ... và sau đó nó chợt nhận ra tôi;)
Stephan202

@martin: phiên bản thứ hai có vẻ tốt hơn nếu bạn hỏi tôi :)
Stephan202

3
//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

Sử dụng chuỗi.Builder nhanh hơn khoảng 3 lần so với việc sử dụng nối chuỗi


1
Tôi tự hỏi, tại sao câu hỏi này không có số phiếu ủng hộ mặc dù là câu trả lời chính xác nhất
Nilesh

3

Ở đây khá khác biệt, tôi sẽ nói cách tiếp cận chức năng hơn, không được liệt kê trong số các câu trả lời khác:

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

Tôi khá chắc rằng nó không phải là giải pháp nhanh nhất, nhưng nó cho thấy cách biến trả về retđược giữ trong trạng thái đóng để xử lý thêm, bởi mỗi hàm trì hoãn.
Vladimir Bauer

Chậm và không xử lý việc kết hợp các ký tự đúng cách.
dolmen

1
Tôi không chắc nó nhanh như thế nào, nhưng nó đẹp.
donatJ

Hiệu suất của cái này có thể được cải thiện trong Go 1.14. Ít nhất các ghi chú phát hành tuyên bố không có chi phí trì hoãn.
Vladimir Bauer

2

Đây là cách thực hiện nhanh nhất

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

Bạn có đánh giá các giải pháp trước khi tuyên bố rằng đó là giải pháp triển khai nhanh nhất không?
Denys Séguret

vâng, tôi đã làm, đó là lý do tại sao có mã BenchmarkReverse :). Tuy nhiên tôi không có kết quả nữa.
rmuller

Giải pháp nhanh, nhưng vẫn sai vì nó không xử lý việc kết hợp các ký tự đúng cách.
dolmen

Có đúng như @dolmen nói rằng điều này không xử lý việc kết hợp các ký tự không? Có một giải pháp ở đây không?
geraldss

2

Mã này giữ nguyên các chuỗi kết hợp các ký tự và cũng sẽ hoạt động với đầu vào UTF-8 không hợp lệ.

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

Nó có thể hiệu quả hơn một chút nếu các nguyên thủy unicode / chuẩn cho phép lặp qua các ranh giới của một chuỗi mà không cần phân bổ. Xem thêm https://code.google.com/p/go/issues/detail?id=9055 .


Không có "đầu vào UTF-8 không hợp lệ" như vậy trong các giá trị chuỗi: khi chuyển đổi từ []bytesang stringGo sẽ thay thế "đầu vào UTF-8 không hợp lệ" bằng một điểm mã hợp lệ \uFFFD.
dolmen

Tôi không hiểu nhận xét trên. Bạn đang nói rằng hành vi của mã này là sai khi được hiển thị với một chuỗi chứa UTF-8 không hợp lệ?
rog

Không. Tôi đang nói rằng UTF-8 không hợp lệ trong Lượt đi stringkhông tồn tại. Nhưng nó có thể tồn tại trong một []byte.
dolmen

Một chuỗi Go có thể chứa chính xác số lượng utf-8 không hợp lệ như một byte []. Ví dụ: play.golang.org/p/PG0I4FJfEN
rog

2

Nếu bạn cần xử lý các cụm grapheme, hãy sử dụng mô-đun unicode hoặc 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
}

Tôi muốn tặng bạn 1.000 phiếu ủng hộ. Tất cả các triển khai khác trên trang này đảo ngược STRING không chính xác (STRING KHÔNG phải là một chuỗi ký tự).
Stefan Steiger

Điều này không hoạt động. Nếu bạn đảo ngược kép chuỗi, bạn sẽ không nhận được chuỗi ban đầu. Kết hợp Diaeresis đứng đầu (\ u0308), được sử dụng trong ví dụ này kết hợp với các ký tự đứng trước tạo âm sắc kép 'a' khi đảo ngược. Nếu strđầu ra được trích dẫn, nó sẽ sửa đổi báo giá hàng đầu!
Joshua Kolden,

2

Bạn cũng có thể nhập một triển khai hiện có:

import "4d63.com/strrev"

Sau đó:

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

Hoặc để đảo ngược một chuỗi bao gồm các ký tự kết hợp unicode:

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

Các triển khai này hỗ trợ thứ tự chính xác của các ký tự đa byte unicode và lược bỏ khi đảo ngược.

Lưu ý: Các hàm đảo ngược chuỗi tích hợp trong nhiều ngôn ngữ lập trình không bảo toàn việc kết hợp và việc xác định các ký tự kết hợp đòi hỏi nhiều thời gian thực thi hơn.


1

Nó chắc chắn không phải là giải pháp hiệu quả nhất về bộ nhớ, nhưng đối với một giải pháp an toàn UTF-8 "đơn giản", những điều sau đây sẽ hoàn thành công việc và không làm hỏng rune.

Theo ý kiến ​​của tôi, đó là nội dung dễ đọc và dễ hiểu nhất trên trang.

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

    return
}

1

Hai phương pháp sau chạy nhanh hơn so với giải pháp nhanh nhất giúp duy trì việc kết hợp các ký tự , mặc dù điều đó không có nghĩa là tôi đang thiếu thứ gì đó trong thiết lập điểm chuẩn của mình.

//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

Phương pháp thứ hai lấy cảm hứng từ điều này

//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

Đây là những gì bạn đang thiếu trong điểm chuẩn của mình: giải pháp của bạn nhanh hơn vì nó không bảo toàn việc kết hợp các ký tự. Nó chỉ là không công bằng khi so sánh chúng.
dolmen

1

LƯU Ý: Câu trả lời này là từ năm 2009, vì vậy có lẽ hiện tại có nhiều giải pháp tốt hơn.


Trông hơi 'vòng vo', và có lẽ không hiệu quả lắm, nhưng minh họa cách giao diện Reader có thể được sử dụng để đọc từ các chuỗi. IntVectors cũng có vẻ rất thích hợp làm bộ đệm khi làm việc với chuỗi utf8.

Nó sẽ thậm chí còn ngắn hơn khi bỏ đi phần 'kích thước' và chèn vào vectơ bằng Chèn, nhưng tôi đoán điều đó sẽ kém hiệu quả hơn, vì toàn bộ vectơ sau đó cần được đẩy lùi lại mỗi lần một chữ rune mới được thêm vào .

Giải pháp này chắc chắn hoạt động với các ký tự 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());
}

Tại sao bạn thêm tất cả những dấu chấm phẩy ở cuối?
Morteza R

@ olivier-mason Đã đến lúc tìm hiểu về gofmt khi chia sẻ mã cờ vây.
dolmen

1
Câu trả lời đó là của tám năm trước.
Oliver Mason

@OliverMason Không bao giờ là quá muộn để sửa (hoặc xóa) một giải pháp không hoàn hảo.
dolmen

0

Một phiên bản mà tôi nghĩ hoạt động trên unicode. Nó được xây dựng dựa trên các hàm 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

rune là một loại, vì vậy hãy sử dụng nó. Hơn nữa, Go không sử dụng dấu chấm phẩy.

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

Nó đã sử dụng dấu chấm phẩy khi câu hỏi đó được đăng.
OneOfOne

Thêm một "giải pháp" sai không xử lý việc kết hợp các ký tự đúng cách.
dolmen


0

Đối với các chuỗi đơn giản, có thể sử dụng cấu trúc như vậy:

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

-1

Đây là một giải pháp khác:

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

Tuy nhiên, giải pháp của yazu ở trên thanh lịch hơn vì anh ta đảo ngược []runelát cắt tại chỗ.


-1

Tuy nhiên, một giải pháp khác (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)
}

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

Kiểm tra

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

Đầu ra

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

Điều này hoạt động nếu đầu vào là NFC. Nhưng như hầu hết các giải pháp sai khác ở đây, nó không hoạt động với việc kết hợp các ký tự.
dolmen

-1
    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
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.