คาถาคืออะไร?


188

คืออะไรruneใน Go?

ฉันได้รับ googling แต่ golang เพียงกล่าวว่าในหนึ่งบรรทัด: เป็นนามแฝงสำหรับruneint32

แต่ทำไมจำนวนเต็มมาใช้รอบ ๆ เหมือนกรณีการแลกเปลี่ยน?

ต่อไปนี้เป็นฟังก์ชั่นการแลกเปลี่ยน ทั้งหมดคืออะไร<=และ-?

และทำไมไม่มี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ให้สามารถส่งคืนสตริงที่สลับกันได้ แต่ผมไม่เข้าใจว่าตรงruneหรือbyteทำงานที่นี่


Sidenote: สิ่งนี้ไม่ได้ทำในสิ่งที่ผู้อ่านอายุน้อยอาจต้องการทำเพื่อคำภาษาอังกฤษ "café"และอื่น ๆ - อย่าพูดภาษาอื่น Go มีห้องสมุดที่มีการสนับสนุนที่ดีสำหรับตัวแปรที่มีประโยชน์จริง ๆ ของการแปลงรูปแบบนี้
RedGrittyBrick

2
ในกรณีที่ใครอยากรู้ว่าคำว่า "rune" มาจากไหน: en.wikipedia.org/wiki/Runic_(Unicode_block)
Matt Browne

[]runeสามารถตั้งค่าให้เป็นแบบบูตัวเลขหรือประเภทสตริง ดูstackoverflow.com/a/62739051/12817546
Tom J

คำตอบ:


149

ตัวอักษรรูนเป็นเพียงค่าจำนวนเต็ม 32 บิต ( อย่างไรก็ตามพวกเขายังคงค่าคงที่ชนิดดังนั้นประเภทของพวกเขาสามารถเปลี่ยนแปลงได้ ) พวกเขาเป็นตัวแทน codepoints 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) unicode.ToLower(r rune) runeไปมีฟังก์ชั่นพิเศษเพื่อแมปไปกรณีที่ต่ำกว่าเช่น
topskip

2
และเพื่อเพิ่ม @ topskip ของคำตอบที่ถูกต้องด้วยฟังก์ชั่น SwapCase ที่ทำงานสำหรับ codepoints ทั้งหมดและไม่เพียง az:func SwapRune(r rune) rune { if unicode.IsUpper(r) { r = unicode.ToLower(r) } else { r = unicode.ToUpper(r) }; return r }
ANisus

22
รูนคือค่า int32 นั่นคือคำตอบทั้งหมด พวกเขาไม่ได้"แมป"
thwd

@AlixAxel: พฤติกรรมของ SimpleFold นั้นเหมือนกัน (โดยใช้ ToLower และ ToUpper สำหรับอักษรรูนส่วนใหญ่) มีบางกรณีที่มันแตกต่างกันเช่น: DZ-> Dz, Dz-> dz, dz-> DZ SwapRune ของฉันจะไปแทน: DZ-> dz, Dz-> DZ, dz-> DZ ผมชอบข้อเสนอแนะของคุณดีขึ้น :)
ANisus

3
ดังนั้นรูนจึงคล้ายกับตัวอักษร C?
Kenny Worden

53

จากบันทึกประจำรุ่น Go lang: http://golang.org/doc/go1#rune

รูนเป็นประเภท หมกมุ่นอยู่กับมัน 32bit และจะหมายถึงการเป็นตัวแทนของUnicode codepoint ในฐานะที่เป็นอุปมาตัวอักษรภาษาอังกฤษตั้งค่าการเข้ารหัสใน 'ASCII' มี 128 คะแนนรหัส ดังนั้นสามารถใส่ในไบต์ (8 บิต) จากนี้ (ผิดพลาด) สมมติฐาน C ได้รับการรักษาตัวอักษรเป็น 'ไบต์' charและ 'สตริง' เป็น char*'ลำดับของตัวละคร

แต่คาดเดาสิ่งที่ มีสัญลักษณ์อื่น ๆ อีกมากมายที่มนุษย์ประดิษฐ์ขึ้นนอกเหนือจากสัญลักษณ์ 'abcde .. ' และมีหลายอย่างที่เราต้องการ 32 บิตในการเข้ารหัส

ใน golang แล้วเป็นลำดับของstring bytesอย่างไรก็ตามเนื่องจากหลายไบต์สามารถแทนจุดรหัส rune ค่าสตริงจึงสามารถมีอักษรรูนได้ ดังนั้นจึงสามารถแปลงเป็น[]runeหรือในทางกลับกัน

แพคเกจ unicode http://golang.org/pkg/unicode/สามารถให้รสชาติของความท้าทายที่หลากหลาย


6
ด้วย Unicode 6.3 ที่ผ่านมามีการกำหนดสัญลักษณ์มากกว่า 110,000 สิ่งนี้ต้องการการแทนจุดรหัสอย่างน้อย 21 บิตดังนั้น a runeจึงเหมือนint32และมีบิตมากมาย
Rick-777

2
คุณพูดว่า "a stringคือลำดับของrunes" - ฉันไม่คิดว่าจริงหรือ? ไปที่บล็อก : "สตริงเป็นเพียงจำนวนไบต์"; Go lang spec : "ค่าสตริงเป็นลำดับ (อาจว่าง) ไบต์"
Chris Martin

1
ฉันยังสับสนอยู่สตริงของรูนหรืออาร์เรย์ของไบต์จึงเป็นเช่นนั้นหรือไม่ พวกเขาใช้แทนกันได้หรือไม่
gogofan

1
@prvn นั่นผิด มันเหมือนกับการบอกว่ารูปภาพไม่ใช่ลำดับของไบต์ แต่เป็นลำดับของพิกเซล แต่ที่จริงภายใต้เป็นชุดของไบต์ สตริงเป็นชุดของไบต์ไม่ใช่อักษรรูน โปรดอ่านข้อมูลจำเพาะ
Inanc Gumus

1
@prvn แต่คุณไม่สามารถพูดnot bytesได้ จากนั้นคุณอาจพูดว่า: "สตริงถูกสร้างขึ้นจากอักษรรูนและอักษรรูนที่ประกอบด้วยไบต์" บางอย่างเช่นนั้น จากนั้นอีกครั้ง มันไม่เป็นความจริงอย่างสมบูรณ์
Inanc Gumus

28

runeฉันได้พยายามที่จะให้ภาษาที่ง่ายของฉันเพื่อให้คนธรรมดาเข้าใจ

คาถาเป็นตัวละคร แค่นั้นแหละ.

มันเป็นตัวละครเดียว มันเป็นตัวละครจากตัวอักษรใด ๆ จากภาษาใดก็ได้จากทุกที่ในโลก

เพื่อให้ได้สตริงที่เราใช้

double-quotes ""

หรือ

back-ticks ``

สตริงแตกต่างจากคาถา ในรูนเราใช้

single-quotes ''

ตอนนี้รูนก็เป็นนามแฝงสำหรับint32... เอ่ออะไรนะ?

เหตุผลที่รูนเป็นชื่อแทนint32เนื่องจากเราเห็นว่ามีรูปแบบการเข้ารหัสเช่นด้านล่าง ป้อนคำอธิบายรูปภาพที่นี่

อักขระแต่ละตัวจับคู่กับตัวเลขดังนั้นมันจึงเป็นหมายเลขที่เราเก็บไว้ ยกตัวอย่างเช่นแมปไป97และเมื่อเราเก็บตัวเลขที่มันเป็นเพียงจำนวนและเพื่อให้คาถาวิธีคือนามแฝงสำหรับ int32 แต่ไม่ได้เป็นเพียงตัวเลขใด ๆ มันเป็นตัวเลขที่มี 32 'ศูนย์และคน' หรือ '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 ไบต์ คุณสามารถแปลงระหว่างสตริงและ [] rune แต่มีความแตกต่างกัน
Eric Wang

2
รูนไม่ได้เป็นตัวอักษรคาถาหมายถึง codepoint unicode และ codepoint ไม่จำเป็นต้องชี้ไปที่ตัวละครตัวหนึ่ง
Inanc Gumus

ควรที่จะเพิ่มว่า "rune ยังเป็นนามแฝงสำหรับ int32" ใช่ แต่ก็ไม่ได้หมายความว่ามันจะมีประโยชน์สำหรับการบีบอัดของคนจน ... ถ้าคุณกด 55296 บางอย่างการแปลงสตริงจะ
ผิดเพี้ยน

27

ฉันไม่มีชื่อเสียงพอที่จะโพสต์ความคิดเห็นต่อคำตอบของ fabrizioM ดังนั้นฉันจะต้องโพสต์ไว้ที่นี่แทน

คำตอบของ Fabrizio นั้นถูกต้องเป็นอย่างมากและแน่นอนว่าเขาได้รับความสำคัญของปัญหาแม้ว่าจะมีความแตกต่างที่จะต้องทำ

สตริงไม่จำเป็นต้องเป็นลำดับของอักษรรูน มันเป็นเสื้อคลุมมากกว่า 'ชิ้นของไบต์' ชิ้นเป็นเสื้อคลุมมากกว่าอาร์เรย์ไป สิ่งนี้แตกต่างกันอย่างไร

คาถาประเภทคือจำเป็นต้องเป็นค่า 32 บิตหมายถึงลำดับของค่าของชนิดคาถาจำเป็นต้องจะมีจำนวนบิต * x 32 บาง สตริงเป็นลำดับไบต์แทนมีความยาวของ x * 8 บิต หากสตริงทั้งหมดเป็นจริงใน Unicode ความแตกต่างนี้จะไม่มีผลกระทบ อย่างไรก็ตามเนื่องจากสตริงเป็นส่วนหนึ่งของไบต์ดังนั้น Go จึงสามารถใช้ ASCII หรือการเข้ารหัสไบต์อื่นใดก็ได้

อย่างไรก็ตามตัวอักษรสตริงจะต้องถูกเขียนลงในแหล่งที่เข้ารหัสใน UTF-8

แหล่งที่มาของข้อมูล: http://blog.golang.org/strings


1
จุดดี ! แต่ละรูนต้องใช้ 4 ไบต์ แต่อักขระแต่ละตัวในสตริงจะถูกเข้ารหัสด้วย utf8 ดังนั้นส่วนใหญ่จะเป็น 1 ~ 3 ไบต์เท่านั้น
Eric Wang

16

(มีความรู้สึกว่าคำตอบข้างต้นยังไม่ได้ระบุความแตกต่างและความสัมพันธ์ระหว่างstringและ[]runeชัดเจนมากดังนั้นฉันจะพยายามเพิ่มคำตอบด้วยตัวอย่าง)

ตามที่@Strangeworkได้รับคำตอบstringและ[]runeเงียบแตกต่างกัน

ความแตกต่าง - string& []rune:

  • string valueเป็นชิ้นไบต์แบบอ่านอย่างเดียว และสตริงตัวอักษรถูกเข้ารหัสใน utf-8 ถ่านแต่ละตัวstringจะใช้เวลา1 ~ 3ไบต์ในขณะที่แต่ละตัวruneใช้เวลา4ไบต์
  • สำหรับstringทั้งสองlen()และดัชนีจะขึ้นอยู่กับไบต์
  • สำหรับ[]runeทั้งสองlen()และดัชนีจะขึ้นอยู่กับ rune (หรือ int32)

ความสัมพันธ์ - string& []rune:

  • เมื่อคุณแปลงจากstringเป็น[]runeแต่ละอักขระ utf-8 ในสตริงนั้นจะกลายเป็นruneถ่านในสตริงที่จะกลายเป็น
  • ในทำนองเดียวกันในการแปลงกลับเมื่อแปลงจาก[]runeไปstringแต่ละruneกลายเป็น UTF-8 stringถ่านใน

เคล็ดลับ:

  • คุณสามารถแปลงระหว่าง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()ในสตริงจะขึ้นอยู่กับไบต์จึงพิมพ์บรรทัดแรกlen: 11
    • เนื่องจากดัชนีบนสตริงยังขึ้นอยู่กับไบต์ด้วยเหตุนี้ 2 บรรทัดต่อไปนี้จึงพิมพ์ค่าประเภทuint8(เนื่องจากbyteเป็นประเภทนามแฝงของuint8, ในระหว่างเดินทาง)
  • เมื่อแปลงstringไป[]runeก็พบ 7 ตัวอักษร utf8 จึง 7 รูน

    • ตั้งแต่len()เมื่อวันที่อยู่บนพื้นฐานของคาถาจึงบรรทัดสุดท้ายที่พิมพ์[]runelen: 7
    • หากคุณทำงาน[]runeผ่านดัชนีมันจะเข้าถึงฐานในคาถา
      เนื่องจากแต่ละ rune นั้นมาจาก utf8 ถ่านในสายอักขระดั้งเดิมดังนั้นคุณสามารถพูดได้ว่าทั้งสองlen()และการดำเนินการของดัชนี[]runeนั้นขึ้นอยู่กับตัวอักษร utf8

"สำหรับสตริงทั้ง len () และดัชนีจะอิงตามไบต์" คุณช่วยอธิบายอีกหน่อยได้ไหม? เมื่อฉันทำfmt.Println("hello你好"[0])มันจะส่งกลับจุดรหัส UTF-8 ที่แท้จริงแทนไบต์
Julian

@ จูเลียนโปรดดูที่ผลลัพธ์ของโปรแกรมในคำตอบสำหรับs[0]มันพิมพ์s[0]: 104, type: uint8ประเภทคือuint8หมายถึงไบต์ สำหรับ ASCII chars เช่นhutf-8 ยังใช้ไบต์เดียวเพื่อแทนดังนั้นจุดโค้ดจึงเหมือนกับไบต์เดียว แต่สำหรับตัวอักษรจีนเช่นมันใช้ 3 ไบต์
Eric Wang

ชี้แจงตัวอย่าง ผมยกมาให้คุณที่นี่stackoverflow.com/a/62739051/12817546
Tom J

7

คนอื่น ๆ ได้ครอบคลุมส่วนที่เกี่ยวข้องกับอักษรรูนดังนั้นฉันจะไม่พูดเกี่ยวกับเรื่องนี้

อย่างไรก็ตามยังมีคำถามที่เกี่ยวข้องกับการswitchไม่มีข้อโต้แย้งใด ๆ นี่เป็นเพียงเพราะใน Golang switchโดยไม่มีการแสดงออกเป็นวิธีอื่นในการแสดงตรรกะ / อื่น ตัวอย่างเช่นเขียนสิ่งนี้:

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

rune เป็นค่า int32 และดังนั้นจึงเป็นชนิด Go ที่ใช้สำหรับแสดงจุดรหัส Unicode จุดโค้ด Unicode หรือตำแหน่งรหัสเป็นค่าตัวเลขที่โดยปกติจะใช้สำหรับการแสดงอักขระ Unicode เดียว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.