ChatGPT解决这个技术问题 Extra ChatGPT

什么是符文?

Go 中的 rune 是什么?

我一直在谷歌搜索,但 Golang 只在一行中说:runeint32 的别名。

但是整数怎么会像交换案例一样到处使用呢?

下面是一个函数swapcase。 <=- 是什么?

为什么 switch 没有任何参数?

&& 应该表示 ,但 r <= 'z' 是什么?

func SwapRune(r rune) rune {
    switch {
    case 'a' <= r && r <= 'z':
        return r - 'a' + 'A'
    case 'A' <= r && r <= 'Z':
        return r - 'A' + 'a'
    default:
        return r
    }
}

他们中的大多数来自http://play.golang.org/p/H6wjLZj6lW

func SwapCase(str string) string {
    return strings.Map(SwapRune, str)
}

我知道这是将 rune 映射到 string 以便它可以返回交换的字符串。但我不明白 runebyte 究竟是如何工作的。

旁注:这与年轻读者可能希望它为 English word "café"others 做的事情不同 - 更不用说其他语言了。 Go 拥有对这种转换的实际有用变体提供良好支持的库。
如果有人想知道“符文”这个词的来源:en.wikipedia.org/wiki/Runic_(Unicode_block)
[]rune 可以设置为布尔、数字或字符串类型。请参阅stackoverflow.com/a/62739051/12817546

I
Inanc Gumus

符文文字只是 32 位整数值但它们是无类型常量,因此它们的类型可以改变)。它们代表 unicode 代码点。例如,符文文字 'a' 实际上是数字 97

因此,您的程序几乎等同于:

package main

import "fmt"

func SwapRune(r rune) rune {
    switch {
    case 97 <= r && r <= 122:
        return r - 32
    case 65 <= r && r <= 90:
        return r + 32
    default:
        return r
    }
}

func main() {
    fmt.Println(SwapRune('a'))
}

如果您要查看 Unicode 映射,这应该很明显,它与该范围内的 ASCII 相同。此外,32 实际上是字符的大写和小写代码点之间的偏移量。因此,通过将 32 添加到 'A',您得到 'a',反之亦然。


这显然只适用于 ASCII 字符,不适用于 'ä' 之类的附加字符,更不用说像 'ı' (U+0131) 之类的更复杂的情况了。 Go 具有映射到小写的特殊功能,例如 unicode.ToLower(r rune) rune
并使用适用于所有代码点而不仅仅是 az 的 SwapCase 函数添加到@topskip 的正确答案:func SwapRune(r rune) rune { if unicode.IsUpper(r) { r = unicode.ToLower(r) } else { r = unicode.ToUpper(r) }; return r }
符文是 int32 值。这就是全部答案。他们没有“映射”。
@AlixAxel:SimpleFold 的行为本质上是相同的(对于大多数符文,它也使用 ToLower 和 ToUpper)。在某些情况下它会有所不同,例如:DZ->Dz,Dz->dz,dz->DZ。我的 SwapRune 会改为:DZ->dz、Dz->DZ、dz->DZ。我更喜欢你的建议:)
那么符文类似于 C 字符?
I
Inanc Gumus

来自 Go 语言发行说明:http://golang.org/doc/go1#rune

符文是一种类型。它占用 32 位,用于表示 Unicode CodePoint。作为类比,以“ASCII”编码的英文字符集有 128 个代码点。因此能够容纳在一个字节(8位)内。根据这个(错误的)假设,C 将字符视为“字节”char,将“字符串”视为“字符序列”char*

但猜猜怎么了。除了“abcde..”符号之外,人类还发明了许多其他符号。而且有这么多,我们需要 32 位来编码它们。

在 golang 中,stringbytes 的序列。但是,由于多个字节可以表示一个符文代码点,因此字符串值也可以包含符文。因此,它可以转换为 []rune,反之亦然。

unicode 包 http://golang.org/pkg/unicode/ 可以让您体验到挑战的丰富性。


在最近的 Unicode 6.3 中,定义了超过 110,000 个符号。这需要每个代码点至少有 21 位表示,因此 rune 类似于 int32 并且有很多位。
您说“stringrune 的序列” - 我认为这不是真的吗? Go blog: "一个字符串只是一堆字节"; Go lang spec:“字符串值是(可能为空的)字节序列”
我仍然很困惑,那么 string 是一个符文数组还是一个字节数组?它们可以互换吗?
@prvn 那是错误的。这就像说图像不是字节序列,而是像素序列。但是,实际上,在下面,它是一系列字节。 字符串是一系列字节,而不是符文。请阅读spec
@prvn 但是,您不能说 not bytes。然后,您可能会说:“字符串由符文组成,符文由字节组成”之类的。然后再一次。这并不完全正确。
S
Suhail Gupta

我试图让我的语言保持简单,以便外行能够理解rune

符文是一个字符。而已。

它是单个字符。它是来自世界任何地方的任何语言的任何字母表中的字符。

要获取我们使用的字符串

double-quotes ""

或者

back-ticks ``

字符串与符文不同。在符文中,我们使用

single-quotes ''

现在,rune 也是 int32...呃什么的别名?

https://i.stack.imgur.com/JfUIZ.png

每个字符都映射到某个数字,因此它就是我们要存储的数字。例如,a 映射到 97,当我们存储该数字时,它只是数字,因此 rune 是 int32 的别名。但不仅仅是任何数字。它是一个包含 32 个“零和一”或“4”字节的数字。 (注:UTF-8 是一种 4 字节的编码方案)

符文与弦有什么关系?

字符串是符文的集合。在以下代码中:

    package main

    import (
        "fmt"
    )

    func main() {
        fmt.Println([]byte("Hello"))
    }

我们尝试将字符串转换为字节流。输出是:

[72 101 108 108 111]

我们可以看到组成该字符串的每个字节都是一个符文。


A string is not a collection of runes 严格来说,这是不正确的。相反,字符串是一个字节切片,用 utf8 编码。 string 中的每个 char 实际上占用 1 ~ 3 个字节,而每个 rune 占用 4 个字节。您可以在字符串和 []rune 之间进行转换,但它们是不同的。
Rune 不是一个字符,一个 rune 代表一个 unicode 代码点。并且代码点不一定指向一个字符。
值得补充的是“符文也是 int32 的别名”是的,但这并不意味着它对穷人压缩很有用...如果您遇到类似 55296 的内容,则字符串转换会误入歧途:Go Playground
i
informatik01

我没有足够的声望对 fabrizioM 的 answer 发表评论,所以我将不得不在此处发表评论。

Fabrizio 的回答在很大程度上是正确的,他当然抓住了问题的本质——尽管必须做出区分。

字符串不一定是符文序列。它是“字节切片”的包装器,切片是 Go 数组的包装器。这有什么区别?

符文类型必须是 32 位值,这意味着符文类型值的序列必然具有一定数量的 x*32 位。作为字节序列的字符串,其长度为 x*8 位。如果所有字符串实际上都是 Unicode,那么这种差异不会产生任何影响。然而,由于字符串是字节切片,Go 可以使用 ASCII 或任何其他任意字节编码。

但是,字符串文字需要写入以 UTF-8 编码的源代码中。

信息来源:http://blog.golang.org/strings


好点子 !每个 rune 需要 4 个字节,但是 string 中的每个字符都是用 utf8 编码的,因此最多只有 1 ~ 3 个字节。
i
involtus

(感觉上面的答案仍然没有很清楚地说明 string[]rune 之间的差异和关系,所以我会尝试添加另一个答案并举例说明。)

正如 @Strangework 的回答所说,string[]rune 完全不同。

差异 - string & []rune

字符串值是一个只读字节切片。并且,字符串文字以 utf-8 编码。 string 中的每个 char 实际上占用 1 ~ 3 个字节,而每个 rune 占用 4 个字节

对于字符串,len() 和 index 都是基于字节的。

对于 []rune,len() 和 index 都基于 rune(或 int32)。

关系 - string & []rune

当您从字符串转换为 []rune 时,该字符串中的每个 utf-8 字符都会变成一个 rune。

同样,在反向转换中,当从 []rune 转换为 string 时,每个 rune 都成为字符串中的一个 utf-8 char。

提示:

您可以在字符串和 []rune 之间进行转换,但它们在类型和整体大小上仍然不同。

(我会添加一个例子来更清楚地表明这一点。)

代码

string_rune_compare.go:

// string & rune compare,
package main

import "fmt"

// string & rune compare,
func stringAndRuneCompare() {
    // string,
    s := "hello你好"

    fmt.Printf("%s, type: %T, len: %d\n", s, s, len(s))
    fmt.Printf("s[%d]: %v, type: %T\n", 0, s[0], s[0])
    li := len(s) - 1 // last index,
    fmt.Printf("s[%d]: %v, type: %T\n\n", li, s[li], s[li])

    // []rune
    rs := []rune(s)
    fmt.Printf("%v, type: %T, len: %d\n", rs, rs, len(rs))
}

func main() {
    stringAndRuneCompare()
}

执行:

去运行 string_rune_compare.go

输出:

hello你好, type: string, len: 11
s[0]: 104, type: uint8
s[10]: 189, type: uint8

[104 101 108 108 111 20320 22909], type: []int32, len: 7

解释:

字符串 hello你好 长度为 11,因为前 5 个字符每个只占 1 个字节,而后 2 个中文字符每个占 3 个字节。因此,总字节数 = 5 * 1 + 2 * 3 = 11 由于字符串上的 len() 基于字节,因此第一行打印 len: 11 由于字符串上的索引也基于字节,因此以下 2 行打印值uint8 类型(因为 byte 是 uint8 的别名类型,在 go 中)。

因此,总字节数 = 5 * 1 + 2 * 3 = 11

由于字符串上的 len() 是基于字节的,因此第一行打印 len: 11

由于字符串上的索引也是基于字节的,因此以下 2 行打印 uint8 类型的值(因为 byte 是 uint8 的别名类型,在 go 中)。

将字符串转换为 []rune 时,发现 7 个 utf8 字符,因此有 7 个 rune。由于 []rune 上的 len() 是基于 rune 的,因此最后一行打印 len: 7. 如果通过索引操作 []rune,它将访问基于 rune。由于每个 rune 都来自原始字符串中的 utf8 字符,因此您也可以说 []rune 上的 len() 和索引操作都基于 utf8 字符。

由于 []rune 上的 len() 是基于 rune 的,因此最后一行打印了 len: 7。

如果你通过索引操作[]rune,它会根据rune来访问。由于每个 rune 都来自原始字符串中的 utf8 字符,因此您也可以说 []rune 上的 len() 和索引操作都基于 utf8 字符。


“对于字符串,len() 和索引都是基于字节的。”你能再解释一下吗?当我执行 fmt.Println("hello你好"[0]) 时,它返回实际的 UTF-8 代码点而不是字节。
@Julian 请看一下答案中程序的输出,对于s[0],它打印s[0]: 104, type: uint8,类型为uint8,表示它是一个字节。对于像 h utf-8 这样的 ASCII 字符也是用单字节来表示,所以码位和单字节一样;但是对于像 这样的中文字符,它使用 3 个字节。
澄清的例子。我在这里引用了你stackoverflow.com/a/62739051/12817546
S
Shashank Goyal

符文相关的部分大家都讲过了,我就不多说了。

但是,还有一个与 switch 没有任何参数有关的问题。这仅仅是因为在 Golang 中,不带表达式的 switch 是表达 if/else 逻辑的另一种方式。例如,这样写:

t := time.Now()
switch {
case t.Hour() < 12:
    fmt.Println("It's before noon")
default:
    fmt.Println("It's after noon")
}

和写这个一样:

t := time.Now()
if t.Hour() < 12 {
    fmt.Println("It's before noon")
} else {
    fmt.Println("It's after noon")
}

您可以阅读更多here


R
Remario

rune 是一个 int32 值,因此它是一种 Go 类型,用于表示 Unicode 代码点。 Unicode 代码点或代码位置是通常用于表示单个 Unicode 字符的数值;


d
dpaks

程序

package main

import (
    "fmt"
)

func main() {
    words := "€25 or less"
    fmt.Println("as string slice")
    fmt.Println(words, len(words))

    runes := []rune(words)
    fmt.Println("\nas []rune slice")
    fmt.Printf("%v, len:%d\n", runes, len(runes))

    bytes := []byte(words)
    fmt.Println("\nas []byte slice")
    fmt.Printf("%v, len:%d\n", bytes, len(bytes))
}

输出

as string slice
€25 or less 13

as []rune slice
[8364 50 53 32 111 114 32 108 101 115 115], len:11

as []byte slice
[226 130 172 50 53 32 111 114 32 108 101 115 115], len:13

如您所见,欧元符号“€”由 3 个字节表示 - 226、130 和 172。符文表示一个字符 - 任何字符,无论是象形文字。一个符文的 32 位足以代表当今世界上的所有字符。因此,欧元符号“€”的符文表示是 8364。

对于 128 个 ASCII 字符,一个字节(8 位)就足够了。因此,数字或字母的符文和字节表示是相同的。例如:2 用 50 表示。

字符串的字节表示在长度上始终大于或等于其符文表示,因为某些字符由超过一个字节但在 32 位之内表示,这就是符文。

https://play.golang.org/p/y93woDLs4Qe


C
Clement Olaniyan

rune 是 int32 的别名,在所有方面都等效于 int32。它用于区分字符值和整数值。

l = 108,o = 111


C
Code Whisperer

Rune 是 int32 类型的别名。它表示单个 Unicode 代码点。 Unicode 联盟将数字值(称为代码点)分配给超过一百万个唯一字符。例如,65 是字母 A、66 -> B 的代码点(来源:Get Programming with Go)