tags:

views:

661

answers:

7

How can we reverse a simple string in Go? A Perl-like 'reverse' function does not seem to exist there.

A: 

Char by char? [and some padding]

+2  A: 

I have not been able to find a built-in function for that (yet). However, there is a reverse example in effective go:

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

This will not work if a is of type string, however, since in Go strings are immutable. Martin Clayton solves this by splitting and joining a given string. The following is an alternative solution, which unfortunately only works for ascii strings:

import "strings"

func Reverse(input string) string {
  b := strings.Bytes(input);
  for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
    b[i], b[j] = b[j], b[i]
  }
  return string(b);
}
Stephan202
Is there a way that doesn't hurt my brain?
DoR
It's worse. Strings are immutable, so the above code does not work for strings. I'll delete it for now.
Stephan202
Now undeleted with a working version.
Stephan202
I suspect that this will fail spectacularly on anything other than ASCII characters.
Robert P
@Robert: just tried; indeed it does ;)
Stephan202
Ok, I get how this works now, I was reading it wrong before @_@. Maybe you should add some parentheses.
DoR
@Pynt: you raise an interesting point, namely readability. I usually *hate* it when binary operators are not surrounded by spaces, but if I would add spaces around `+` and `-` here, it would be even less readable...
Stephan202
@Pynt: I also wonder why many people uses so many func calls like NewReader, ReadRune, RuneStart etc, although it can be done mostly using range and []int only. My solution: http://stackoverflow.com/questions/1752414/how-to-reverse-a-string-in-go/1758098#1758098
yuku
+4  A: 

Building on Stephan202's original suggestion, and appears to work for unicode strings:

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

Alternate, not using strings package, but not '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 );
}
martin clayton
+1. That works. But I must say that it is rather odd (for now) that splitting and joining is necessary for such a simple task...
Stephan202
@martin: sorry for that edit. I accidentally pasted my updated answer in your question... *me very ashamed*.
Stephan202
I attempted a rollback. Hope I got it right.
Nosredna
@Stephan - no problem. I added an alternate solution, based on the strings package Bytes function.
martin clayton
@Nosradena: I rolled back within the same minute (I was surprised to see that Martin updated his answer with exactly the same text I had just written... and then it dawned on me ;)
Stephan202
@Nosredna - looks right I think - thanks.
martin clayton
@martin: the second version looks better if you ask me :)
Stephan202
+1  A: 

A version which I think works on unicode. It is built on the utf8.Rune functions:

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);
}
Jonathan Wright
+6  A: 

Russ Cox, on the golang-nuts mailing list, suggests

package main 
func main() { 
        input := "The quick brown 狐 jumped over the lazy 犬"; 
        // Get Unicode code points. 
        n := 0; 
        rune := make([]int, 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); 
        print(output, "\n"); 
}
Ben Bullock
I like how they force you to think about encodings.
Jurily
off-topic: why is it [golang-nuts] and not [go-nuts]?
Jimmy
+3  A: 

Looks a bit 'roundabout', and probably not very efficient, but illustrates how the Reader interface can be used to read from strings. IntVectors also seem very suitable as buffers when working with utf8 strings.

It would be even shorter when leaving out the 'size' part, and insertion into the vector by Insert, but I guess that would be less efficient, as the whole vector then needs to be pushed back by one each time a new rune is added.

This solution definitely works with utf8 characters.

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());
}
Oliver Mason
+5  A: 

This works on unicode strings by considering 2 things:

  • range works on string by enumerating unicode characters
  • string can be constructed from int slices where each element is a unicode character.

So here it goes:

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);
}
yuku
I would assign `i:=len(o)-1` and then fold the for into a single line `for _, c:=range s { o[i--]=c; }`. Man I HATE the for without parentheses - is this allowed: `for(_, c:=range s) { o[i--]=c; }`
Software Monkey
Could you explain what the _ does?
Software Monkey
@Software_Monkey: o[i--] = c is not allowed in Go. -- and ++ are statements, not expressions. _ means to discard (ignore) that variable.
yuku