Rune là gì?


185

Một runetrong Go là gì?

Tôi đã googling nhưng Golang chỉ nói trong một dòng: runelà bí danh choint32 .

Nhưng làm thế nào đến số nguyên được sử dụng xung quanh như trường hợp hoán đổi?

Sau đây là một hoán đổi chức năng. Tất cả là gì <=-?

Và tại sao không switchcó bất kỳ đối số?

&&nên có ý nghĩa nhưng những gì là 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
    }
}

Hầu hết trong số họ đến từ http://play.golang.org/p/H6wjLZj6lW

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

Tôi hiểu đây là ánh xạ runeđể stringnó có thể trả về chuỗi đã tráo đổi. Nhưng tôi không hiểu chính xác runehoặc bytehoạt động ở đây.


Sidenote: Điều này không làm những gì độc giả nhỏ tuổi có thể muốn nó làm cho từ tiếng Anh "café"những người khác - chứ đừng nói đến các ngôn ngữ khác. Go có các thư viện với sự hỗ trợ tốt cho các biến thể thực sự hữu ích của loại chuyển đổi này.
RedGrittyBrick

2
Trong trường hợp bất cứ ai cũng muốn biết từ "rune" đến từ đâu: en.wikipedia.org/wiki/Runic_(Unicode_block)
Matt Browne

Câu trả lời:


146

Chữ Rune chỉ là các giá trị nguyên 32 bit ( tuy nhiên chúng là các hằng số chưa được gõ, vì vậy loại của chúng có thể thay đổi ). Họ đại diện cho các điểm mã unicode. Ví dụ, chữ rune 'a'thực sự là số 97.

Do đó, chương trình của bạn tương đối nhiều với:

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

Rõ ràng, nếu bạn nhìn vào ánh xạ Unicode, giống hệt với ASCII trong phạm vi đó. Hơn nữa, 32 trên thực tế là phần bù giữa mật mã chữ hoa và chữ thường của ký tự. Vì vậy, bằng cách thêm 32vào 'A', bạn nhận được 'a'và ngược lại.


12
Điều này rõ ràng chỉ hoạt động đối với các ký tự ASCII chứ không phải cho các ký tự được tạo ra, chẳng hạn như 'ä', chứ đừng nói đến các trường hợp phức tạp hơn như '' '(U + 0131). Go có các chức năng đặc biệt để ánh xạ đến chữ thường như unicode.ToLower(r rune) rune.
topskip

2
Và để thêm vào câu trả lời đúng của @ topskip với chức năng SwapCase hoạt động cho tất cả các loại tiền mã hóa và không chỉ az:func SwapRune(r rune) rune { if unicode.IsUpper(r) { r = unicode.ToLower(r) } else { r = unicode.ToUpper(r) }; return r }
ANisus

22
Các giai điệu là giá trị int32. Đó là toàn bộ câu trả lời. Chúng không được "lập bản đồ" .
thwd

@AlixAxel: Hành vi của SimpleFold về cơ bản là giống nhau (Nó cũng sử dụng ToLower và ToUpper cho hầu hết các rune). Có một số trường hợp nó khác nhau như:-> Dz, Dz-> dz,->. SwapRune của tôi thay vào đó sẽ đi:-> dz, Dz->,->. Tôi thích đề xuất của bạn hơn :)
ANisus

3
Vậy rune có giống với ký tự C không?
Kenny Worden

52

Từ ghi chú phát hành Go lang: http://golang.org/doc/go1#rune

Rune là một loại. Nó chiếm 32 bit và có nghĩa là đại diện cho Unicode CodePoint . Tương tự như các ký tự tiếng Anh được mã hóa trong 'ASCII' có 128 điểm mã. Do đó có thể nằm gọn trong một byte (8 bit). Từ giả định (sai lầm) này, C đã coi các ký tự là 'byte' charvà 'chuỗi' là 'chuỗi ký tự' char*.

Nhưng đoán xem. Có nhiều biểu tượng khác được phát minh bởi con người ngoài các biểu tượng 'abcde ..'. Và có rất nhiều thứ mà chúng ta cần 32 bit để mã hóa chúng.

Trong golang thì a stringlà một chuỗi bytes. Tuy nhiên, vì nhiều byte có thể biểu thị một điểm mã rune, nên một giá trị chuỗi cũng có thể chứa rune. Vì vậy, nó có thể được chuyển đổi thành a []rune, hoặc ngược lại.

Gói unicode http://golang.org/pkg/unicode/ có thể mang đến một hương vị của sự phong phú của thử thách.


6
Với Unicode 6.3 gần đây, có hơn 110.000 ký hiệu được xác định. Điều này đòi hỏi ít nhất 21 bit đại diện cho mỗi điểm mã, vì vậy a runegiống int32và có nhiều bit.
Rick-777

2
Bạn nói "a stringlà một chuỗi runes" - Tôi không nghĩ đó là sự thật? Đi blog : "một chuỗi chỉ là một bó byte"; Go lang spec : "Giá trị chuỗi là một chuỗi byte (có thể trống)"
Chris Martin

1
Tôi vẫn còn bối rối, vậy chuỗi là một chuỗi rune hay một mảng byte? Họ có thể thay thế cho nhau?
gogofan

1
@prvn Điều đó sai. Giống như nói một hình ảnh không phải là một chuỗi byte, nó là một chuỗi các pixel. Nhưng, thực ra, bên dưới, đó là một chuỗi byte. Một chuỗi là một chuỗi các byte, không phải rune. Xin vui lòng đọc thông số kỹ thuật .
Inanc Gumus

1
@prvn Nhưng, bạn không thể nói not bytes. Sau đó, bạn có thể nói: "Chuỗi được tạo thành từ rune và rune được tạo thành từ byte" Một cái gì đó như thế. Sau đó một lần nữa. nó không hoàn toàn đúng
Inanc Gumus

27

Tôi đã cố gắng giữ cho ngôn ngữ của tôi đơn giản để một giáo dân hiểu rune.

Một rune là một nhân vật. Đó là nó.

Đó là một nhân vật duy nhất. Đó là một nhân vật từ bất kỳ bảng chữ cái từ bất kỳ ngôn ngữ từ bất cứ nơi nào trên thế giới.

Để có được một chuỗi chúng tôi sử dụng

double-quotes ""

HOẶC LÀ

back-ticks ``

Một chuỗi khác với một rune. Trong rune chúng tôi sử dụng

single-quotes ''

Bây giờ một rune cũng là một bí danh cho int32... Uh Gì?

Lý do rune là một bí danh int32là vì chúng ta thấy rằng với các sơ đồ mã hóa như dưới đây nhập mô tả hình ảnh ở đây

mỗi ký tự ánh xạ tới một số và do đó, đó là số mà chúng tôi đang lưu trữ. Ví dụ, một bản đồ để 97 và khi chúng tôi lưu trữ số mà nó chỉ là số lượng và do đó cách rune là một bí danh cho int32. Nhưng không chỉ là bất kỳ số nào. Đó là một số có 32 byte số 0 và số 'hoặc' 4 'byte. (Lưu ý: UTF-8 là sơ đồ mã hóa 4 byte)

Làm thế nào runes liên quan đến chuỗi?

Một chuỗi là một tập hợp các rune. Trong đoạn mã sau:

    package main

    import (
        "fmt"
    )

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

Chúng tôi cố gắng chuyển đổi một chuỗi thành một luồng byte. Đầu ra là:

[72 101 108 108 111]

Chúng ta có thể thấy rằng mỗi byte tạo nên chuỗi đó là một rune.


2
A string is not a collection of runesĐiều này không đúng một cách nghiêm túc. Thay vào đó, chuỗi là một lát byte, được mã hóa bằng utf8. Mỗi char trong chuỗi thực sự mất 1 ~ 3 byte, trong khi mỗi rune mất 4 byte. Bạn có thể chuyển đổi giữa chuỗi và [] rune, nhưng chúng khác nhau.
Eric Wang

2
Rune không phải là một nhân vật, một rune đại diện cho một mật mã unicode. Và một mật mã không nhất thiết phải trỏ đến một ký tự.
Inanc Gumus

Đáng nói thêm rằng "một rune cũng là bí danh của int32" có, nhưng điều đó không có nghĩa là nó hữu ích cho việc nén người nghèo ... Nếu bạn nhấn một cái gì đó như 55296, việc chuyển đổi chuỗi sẽ đi lạc hướng: Go Playground
kubanchot

26

Tôi không có đủ danh tiếng để đăng bình luận cho câu trả lời của fabrizioM , vì vậy tôi sẽ phải đăng nó ở đây để thay thế.

Câu trả lời của Fabrizio phần lớn là chính xác, và ông chắc chắn đã nắm bắt được bản chất của vấn đề - mặc dù có một sự khác biệt phải được thực hiện.

Một chuỗi KHÔNG nhất thiết phải là một chuỗi rune. Nó là một trình bao bọc trên 'lát byte', một lát là trình bao bọc trên mảng Go. Điều này có gì khác biệt?

Một rune loại nhất thiết phải là một giá trị 32-bit, có nghĩa là một chuỗi các giá trị của các loại rune nhất thiết sẽ có một số số bit x * 32. Các chuỗi, là một chuỗi byte, thay vào đó có độ dài x * 8 bit. Nếu tất cả các chuỗi thực sự bằng Unicode, sự khác biệt này sẽ không có tác động. Do các chuỗi là các lát byte , tuy nhiên, Go có thể sử dụng ASCII hoặc bất kỳ mã hóa byte tùy ý nào khác.

Tuy nhiên, chuỗi ký tự được yêu cầu phải được ghi vào nguồn được mã hóa trong UTF-8.

Nguồn thông tin: http://blog.golang.org/strings


1
Điểm tốt ! Mỗi rune yêu cầu 4 byte, nhưng mỗi ký tự trong chuỗi được mã hóa bằng utf8, do đó, tối đa 1 ~ 3 byte.
Eric Wang

15

(Có cảm giác rằng các câu trả lời ở trên vẫn không nêu rõ sự khác biệt & mối quan hệ giữa string[]runerất rõ ràng, vì vậy tôi sẽ cố gắng thêm một câu trả lời khác bằng ví dụ.)

Như @Strangeworkcâu trả lời đã nói, string[]runeyên lặng khác nhau.

Sự khác biệt - string& []rune:

  • string valuelà một lát byte chỉ đọc. Và, một chuỗi ký tự được mã hóa trong utf-8. Mỗi char stringthực sự mất 1 ~ 3 byte, trong khi mỗi char runemất 4 byte
  • Đối với string, cả len()và chỉ mục được dựa trên byte.
  • Đối với []rune, cả len()và chỉ mục đều dựa trên rune (hoặc int32).

Mối quan hệ - string& []rune:

  • Khi bạn chuyển đổi từ stringsang []rune, mỗi char utf-8 trong chuỗi đó sẽ trở thành a rune.
  • Tương tự, trong chuyển đổi ngược lại, khi chuyển đổi từ []runesang string, mỗi cái runesẽ trở thành một char utf-8 trong string.

Lời khuyên:

  • Bạn có thể chuyển đổi giữa string[]rune, nhưng chúng vẫn khác nhau, ở cả loại & kích thước tổng thể.

(Tôi sẽ thêm một ví dụ để cho thấy rõ hơn.)


chuỗi_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()
}

Hành hình:

chạy chuỗi_rune_compare.go

Đầu ra:

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

Giải trình:

  • Chuỗi hello你好có độ dài 11, bởi vì 5 ký tự đầu tiên, mỗi ký tự chỉ mất 1 byte, trong khi 2 ký tự Trung Quốc cuối cùng chỉ có 3 byte.

    • Như vậy total bytes = 5 * 1 + 2 * 3 = 11
    • len()trên chuỗi dựa trên byte, do đó, dòng đầu tiên được inlen: 11
    • Vì chỉ mục trên chuỗi cũng dựa trên byte, do đó, 2 dòng sau sẽ in các giá trị loại uint8(vì bytelà loại bí danh của uint8, trong go).
  • Khi chuyển đổi stringthành []rune, nó tìm thấy 7 ký tự utf8, do đó 7 rune.

    • Từ len()trên []runeđược dựa trên rune, do đó dòng cuối cùng in len: 7.
    • Nếu bạn hoạt động []runethông qua chỉ mục, nó sẽ truy cập cơ sở trên rune.
      Vì mỗi rune là từ một char utf8 trong chuỗi ban đầu, do đó bạn cũng có thể nói cả hai len()và hoạt động chỉ mục []runedựa trên các ký tự utf8.

"Đối với chuỗi, cả len () và chỉ mục đều dựa trên byte." Bạn có thể giải thích thêm một chút? Khi tôi làm điều fmt.Println("hello你好"[0])đó sẽ trả về điểm mã UTF-8 thực tế thay vì byte.
Julian

@Julian Hãy xem đầu ra của chương trình trong câu trả lời, vì s[0], nó in s[0]: 104, type: uint8, loại là uint8, có nghĩa là một byte. Đối với các ký tự ASCII như hutf-8 cũng sử dụng một byte đơn để biểu diễn nó, vì vậy điểm mã giống như byte đơn; nhưng đối với ký tự tiếng Trung như , nó sử dụng 3 byte.
Eric Wang

7

Mọi người khác đã đề cập đến phần liên quan đến rune, vì vậy tôi sẽ không nói về điều đó.

Tuy nhiên, cũng có một câu hỏi liên quan đến việc switchkhông có bất kỳ đối số. Điều này đơn giản là vì trong Golang, switchkhông có biểu thức là một cách thay thế để diễn đạt logic / khác. Ví dụ, viết này:

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

cũng giống như viết này:

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

Bạn có thể đọc thêm ở đây .


0

Rune là một giá trị int32 và do đó, nó là loại Go được sử dụng để thể hiện một điểm mã Unicode. Điểm mã hoặc vị trí mã Unicode là một giá trị số thường được sử dụng để thể hiện các ký tự Unicode đơn;

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.