什么是符文?


186

什么是runeGo?

我一直在谷歌搜索,但Golang只说了一行:rune是的别名int32

但是,为什么像交换案例一样在整数周围使用整数呢?

以下是函数交换案例。什么都<=-

为什么没有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在这里工作。


旁注:这并不能满足年轻读者对英语单词“café”其他单词的期望,更不用说其他语言了。Go的库对此类转换的实际有用变体提供了不错的支持。
RedGrittyBrick

2
如果有人想知道“符文”一词的来源:en.wikipedia.org/wiki/Runic_(Unicode_block)
Matt Browne

Answers:


146

符文文字只是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',反之亦然。


12
显然,这仅适用于ASCII字符,不适用于诸如“ä”之类的附加字符,更不用说诸如“ı”(U + 0131)之类的更复杂的情况了。Go具有映射到小写字母的特殊功能,例如unicode.ToLower(r rune) rune
13年

2
并为SwapCase函数添加到@topskip的正确答案,该函数适用于所有代码点,而不仅适用于az:func SwapRune(r rune) rune { if unicode.IsUpper(r) { r = unicode.ToLower(r) } else { r = unicode.ToUpper(r) }; return r }
ANisus 2013年

22
符文是int32值。这就是全部答案。它们不是“映射”的
2013年

@AlixAxel:SimpleFold的行为基本相同(大多数符文也使用ToLower和ToUpper)。在某些情况下,它们会有所不同,例如:DZ->Dz,Dz->dz,dz->DZ。我的SwapRune会改为:DZ->dz,Dz->DZ,dz->DZ。我更喜欢您的建议:)
ANisus 2014年

3
那么,符文类似于C字符?
肯尼·沃登17'Feb

52

从Go lang发行说明中: http //golang.org/doc/go1#rune

符文是一种类型。它占用32位,用于表示Unicode CodePoint。类似地,以“ ASCII”编码的英文字符集具有128个代码点。因此可以放入一个字节(8位)内。从这个(错误的)假设中,C将字符视为“字节” char,并将“字符串”视为“字符序列”char*

但猜猜怎么了。除“ abcde ..”符号外,还有许多其他人类发明的符号。太多了,我们需要32位对其进行编码。

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

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


6
在最新的Unicode 6.3中,定义了超过110,000个符号。这要求每个代码点至少有21位的表示形式,因此a rune就像int32并且具有很多位。
Rick-777,13年

2
您说“ a stringrunes 的序列”-我认为这不是真的吗?去博客:“一个字符串只是一堆字节”;Go lang规范:“字符串值是字节序列(可能为空)”
克里斯·马丁

1
我仍然很困惑,所以字符串是一个符文数组还是一个字节数组?它们可以互换吗?
gogofan '17

1
@prvn错了。这就像说图像不是字节序列,而是像素序列。但是,实际上,在下面是一系列字节。字符串是一系列字节,而不是符文。请阅读规格
伊南克·古姆斯

1
@prvn但是,您不能说not bytes。然后,您可能会说:“字符串由符文组成,而符文由字节组成”之类的东西。然后再说一次。这不是完全正确的。
伊南克·古姆斯

28

我试图使我的语言简单,以使外行理解rune

符文是一个角色。而已。

它是一个字符。它是来自世界各地任何语言的任何字母的字符。

为了得到一个字符串,我们使用

double-quotes ""

要么

back-ticks ``

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

single-quotes ''

现在,符文也是 int32 ... Uh。

符文是别名的原因int32是因为我们看到了如下的编码方案 在此处输入图片说明

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

符文与字符串有何关系?

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

    package main

    import (
        "fmt"
    )

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

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

[72 101 108 108 111]

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


2
A string is not a collection of runes严格来讲,这是不正确的。相反,字符串是一个字节切片,使用utf8编码。字符串中的每个字符实际上占用1〜3个字节,而每个符文则占用4个字节。您可以在字符串和[]符文之间转换,但是它们是不同的。
埃里克·王

2
符文不是字符,符文表示Unicode代码点。一个代码点不一定指向一个字符。
伊南克·古姆斯

值得补充的是,“一个符文也是int32的别名”是的,但这并不意味着它对于穷人压缩很有用...如果您遇到类似55296的错误,则字符串转换会误入歧途:转到游乐场
kubanczyk

27

我的信誉不足,无法对fabrizioM的答案发表评论,所以我将不得不在这里发布。

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

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

符文类型必然是一个32位的值,这意味着符类型的值的序列,将不可避免地比特×* 32的一些数字。字符串是字节序列,而是具有x * 8位的长度。如果所有字符串实际上都是Unicode,则此差异不会有影响。由于字符串是字节片但是,,所以Go可以使用ASCII或任何其他任意字节编码。

但是,必须将字符串文字写入以UTF-8编码的源中。

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


1
好点子 !每个符文需要4个字节,但是字符串中的每个字符都使用utf8编码,因此最多只能包含1〜3个字节。
Eric Wang

15

(有一种感觉,上面的答案依然没有状态之间的区别和关系string,并[]rune很清楚,所以我会尝试添加与例如另一个答案。)

就像@Strangework答案所说的,string[]rune安静不同。

差异- string[]rune

  • string value是只读字节片。并且,字符串文字以utf-8编码。string实际上,每个字符占用1〜3个字节,而每个字符rune占用4个字节个字节
  • 对于stringlen()和索引均基于字节。
  • 对于[]runelen()和索引都基于符文(或int32)。

关系- string[]rune

  • 当您从转换string[]rune,每个UTF-8字符在该字符串变成一个rune
  • 同样,在反向转换中,当从转换为时,每个转换为[]rune中的utf-8字符。stringrunestring

提示:

  • 您可以在string和之间进行转换[]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个字节。

    • 从而, total bytes = 5 * 1 + 2 * 3 = 11
    • 由于len()on字符串基于字节,因此打印的第一行len: 11
    • 由于字符串上的索引也是基于字节的,因此以下两行将打印类型的值uint8(因为go中byte是别名类型uint8,)。
  • 当转换string[]rune,它发现7个UTF8字符,因此7个符文。

    • 由于len()on []rune基于符文,因此最后一行被打印len: 7
    • 如果[]rune通过索引操作,它将基于符文访问。
      由于每个符文都来自原始字符串中的utf8字符,因此,您也可以说len()和的索引操作[]rune都基于utf8字符。

“对于字符串,len()和index均基于字节。” 您能再解释一下吗?当我这样做时,fmt.Println("hello你好"[0])它将返回实际的UTF-8代码点而不是字节。
朱利安

@Julian请查看答案中的程序输出,因为s[0],它的输出为print s[0]: 104, type: uint8,类型为uint8,表示其为一个字节。对于hutf-8 这样的ASCII字符,也使用单个字节来表示它,因此代码点与单个字节相同。但是对于像这样的中文字符,它使用3个字节。
Eric Wang

7

其他人都涵盖了与符文有关的部分,因此我不再赘述。

但是,还有一个问题是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")
}

您可以在这里阅读更多内容。


0

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.