การแยกสตริงย่อยใน Go


115

ฉันพยายามอ่านทั้งบรรทัดจากคอนโซล (รวมถึงช่องว่าง) จากนั้นประมวลผล เมื่อใช้ bufio.ReadString อักขระขึ้นบรรทัดใหม่จะถูกอ่านพร้อมกับอินพุตดังนั้นฉันจึงคิดรหัสต่อไปนี้เพื่อตัดแต่งอักขระขึ้นบรรทัดใหม่:

input,_:=src.ReadString('\n')
inputFmt:=input[0:len(input)-2]+"" //Need to manually add end of string

มีวิธีสำนวนมากกว่านี้ไหม? นั่นคือมีไลบรารีที่ดูแลไบต์ว่างตอนจบเมื่อแยกสตริงย่อยให้คุณหรือไม่?

(ใช่ฉันรู้ว่ามีวิธีการอ่านบรรทัดโดยไม่ต้องขึ้นบรรทัดใหม่ในgo readline -> stringแต่ฉันกำลังมองหาการจัดการสตริงที่สวยงามมากกว่า)

คำตอบ:


148

ดูเหมือนว่าคุณกำลังสับสนกับการทำงานของชิ้นส่วนและรูปแบบการจัดเก็บสตริงซึ่งแตกต่างจากที่คุณมีใน C

  • ชิ้นใด ๆ ใน Go เก็บความยาว (เป็นไบต์) ดังนั้นคุณไม่ต้องกังวลเกี่ยวกับค่าใช้จ่ายในlenการดำเนินการ: ไม่จำเป็นต้องนับ
  • Go strings จะไม่ถูกยกเลิกด้วย null ดังนั้นคุณจึงไม่จำเป็นต้องลบ null ไบต์และคุณไม่จำเป็นต้องเพิ่ม1หลังจากแบ่งส่วนโดยการเพิ่มสตริงว่าง

หากต้องการลบถ่านสุดท้าย (หากเป็นอักขระแบบหนึ่งไบต์) ให้ทำ

inputFmt:=input[:len(input)-1]

11
คุณไม่จำเป็นต้องใช้ 0 (หรือ :) s = s[:len(s)-1]ก็ทำได้
uriel

8
โปรดทราบว่าวิธีนี้ใช้ไม่ได้กับสตริง Unicode! groups.google.com/forum/#!msg/golang-nuts/ZeYei0IWrLg/…
Melllvar

@Melllvar นั่นทำไมฉัน precised "ถ้าเป็นถ่านหนึ่งไบต์" หากคุณต้องการลบถ่านที่มีขนาดมากกว่าหนึ่งไบต์ (นั่นไม่ใช่กรณีของ OP) คุณต้องปรับตัว
Denys Séguret

25

Go strings จะไม่ถูกยกเลิกด้วย null และหากต้องการลบ char สุดท้ายของสตริงคุณสามารถทำได้:

s = s[:len(s)-1]

10
สิ่งนี้ไม่ถูกต้องและจะทำให้เกิดข้อบกพร่อง สิ่งนี้จะตัดไบต์สุดท้ายออกจากสตริงซึ่งอาจทำให้ UTF-8 ไม่ถูกต้อง (หรือการเข้ารหัสแบบหลายไบต์อื่น ๆ )
ดร. Sybren

3
ดูplay.golang.org/p/K3HBBtj4Oiสำหรับตัวอย่างการหยุดพัก
ดร. Sybren

10

เพื่อหลีกเลี่ยงความตื่นตระหนกในการป้อนข้อมูลที่มีความยาวเป็นศูนย์ให้ห่อการดำเนินการตัดทอนใน if

input, _ := src.ReadString('\n')
var inputFmt string
if len(input) > 0 {
    inputFmt = input[:len(input)-1]
}
// Do something with inputFmt

9

นี่เป็นวิธีง่ายๆในการดำเนินการสตริงย่อยใน Go

package main

import "fmt"

var p = fmt.Println

func main() {

  value := "address;bar"

  // Take substring from index 2 to length of string
  substring := value[2:len(value)]
  p(substring)

}

7

คำเตือน: การดำเนินการกับสตริงเพียงอย่างเดียวจะใช้ได้กับ ASCII เท่านั้นและจะนับผิดเมื่ออินพุตเป็นอักขระที่เข้ารหัสที่ไม่ใช่ ASCII UTF-8 และอาจทำให้อักขระเสียหายด้วยซ้ำเนื่องจากตัดอักขระหลายไบต์กลางลำดับ

นี่คือเวอร์ชันที่รับรู้ UTF-8:

func substr(input string, start int, length int) string {
    asRunes := []rune(input)

    if start >= len(asRunes) {
        return ""
    }

    if start+length > len(asRunes) {
        length = len(asRunes) - start
    }

    return string(asRunes[start : start+length])
}

1
วิธีนี้ต้องการการโหวตเพิ่มมากขึ้น - ฉันเพิ่งถูกกัดอย่างรุนแรงโดยไม่ใช้การแยกการรับรู้ utf-8
kolaente


2

8 ปีต่อมาฉันเจออัญมณีนี้ แต่ฉันไม่เชื่อว่าคำถามดั้งเดิมของ OP ได้รับคำตอบจริงๆ:

ดังนั้นฉันจึงคิดรหัสต่อไปนี้เพื่อตัดแต่งอักขระขึ้นบรรทัดใหม่

ในขณะที่bufio.ReaderประเภทสนับสนุนReadLine() วิธีการที่ทั้งสองลบ\r\nและ\nมีความหมายว่าเป็นฟังก์ชันระดับต่ำซึ่งใช้งานไม่สะดวกเนื่องจากจำเป็นต้องตรวจสอบซ้ำ

IMO วิธีที่เป็นสำนวนในการลบช่องว่างคือการใช้ไลบรารีสตริงของ Golang :

input, _ = src.ReadString('\n')

// more specific to the problem of trailing newlines
actual = strings.TrimRight(input, "\r\n")

// or if you don't mind to trim leading and trailing whitespaces 
actual := strings.TrimSpace(input)

ดูตัวอย่างการใช้งานจริงใน Golang playground: https://play.golang.org/p/HrOWH0kl3Ww

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