反向遍历字符串的范围

huangapple go评论77阅读模式
英文:

Reverse range over a string

问题

如何在Go语言中“反向遍历”字符串的每个字符?
例如,给定s := "some string \u1222 whatever" - 我想要做类似这样的操作:

for i, v := ~reverse~ range s {
}

请注意,我希望通过标准库来解决,而不是自己编写函数。我知道有很多现有的库可以做到这一点,但这与问题无关。此外,我不能使用len(s)并进行如下操作:

for i := len(s) - 1; i >= 0; i-- {
}

因为在Go语言中,内置的len函数只返回字符串中的字节数(对于非ASCII字符串无效)。我也不能使用len(s) - k - 1,其中krange指令提供的索引,原因如上所述。


更新1
可以通过反向(从右到左)查找utf-8rune来实现,因为我们可以通过每个字节或字节组的高位比特轻松识别rune。来自《Go语言编程》一书的内容:
反向遍历字符串的范围
如图所示,我们可以从最后一个字节开始,最多需要向左扫描4个字节才能获取一个rune

英文:

How can I "reverse range" in Go over individual characters of a string?
For example, given s := "some string \u1222 whatever" - I want to do something like:

for i, v := ~reverse~ range s {
}

Please note, that I'm interested in a solution via standard library without having to write a function myself. I'm aware of tons of existing libraries which can do that, but that's irrelevant. Moreover - I can't use len(s) and do:

for i := len(s) - 1; i >= 0; i-- {
}

since in Go built-in len function returns only number of bytes in a string (won't work for non-ASCII strings). I also can't do len(s) - k - 1 where k is an index provided by range instruction due to aforementioned reason.


UPD1:
It is possible to do a reverse (right to left) lookup of utf-8 runes, because we can easily identify runes by high order bits of each byte or groups of bytes. From The Go Programming Language book:
反向遍历字符串的范围
As you can see, we can start from the last byte and we will need to scan to the left at most 4 bytes to get a rune.

答案1

得分: 4

最简单的解决方案是将string转换为[]rune,这样你就可以迭代它,但是以“反向”的方式索引(或者使用向下的循环):

rs := []rune(s)
max := len(rs) - 1
for i := range rs {
    r := rs[max-i]
    fmt.Printf("%c ", r)
}

这将输出(在Go Playground上尝试):

r e v e t a h w   ሢ   g n i r t s   e m o s

如果你想避免[]rune的转换,你可以使用utf8.DecodeLastRuneInString(),像这样:

for {
    r, size := utf8.DecodeLastRuneInString(s)
    if r == utf8.RuneError {
        break
    }
    fmt.Printf("%c ", r)
    s = s[:len(s)-size]
}

这将输出相同的结果,可以在Go Playground上尝试。

英文:

The easiest solution would be to convert the string to []rune, so you can iterate over it, but index "backward" (or use a downward loop):

rs := []rune(s)
max := len(rs) - 1
for i := range rs {
	r := rs[max-i]
	fmt.Printf("%c ", r)
}

This will output (try it on the Go Playground):

r e v e t a h w   ሢ   g n i r t s   e m o s 

If you want to avoid the []rune conversion, you may use utf8.DecodeLastRuneInString() like this:

for {
	r, size := utf8.DecodeLastRuneInString(s)
	if r == utf8.RuneError {
		break
	}
	fmt.Printf("%c ", r)
	s = s[:len(s)-size]
}

This outputs the same, try this one on the Go Playground.

答案2

得分: 1

你可以这样做:

runes := []rune(str)
for x := len(runes) - 1; x >= 0; x-- {
   // 使用 runes[x] 进行操作
}
英文:

You can do:

runes:=[]rune(str)
for x:=len(runes)-1; x>=0; x-- {
   // work with runes[x]
}

</details>



huangapple
  • 本文由 发表于 2021年11月27日 05:59:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/70130406.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定