2014-07-23 12 views
5

Tôi luôn chuyển đổi chuỗi thành [] byte thành chuỗi lặp đi lặp lại. Có rất nhiều chi phí với điều này? Có cách nào tốt hơn?Go: Chi phí chuyển đổi từ [] byte thành chuỗi và ngược lại

Ví dụ, đây là một chức năng chấp nhận một chuỗi UTF8, bình thường hóa nó, loại bỏ dấu trọng âm, sau đó chuyển đổi ký tự đặc biệt để ASCII tương đương:

var transliterations = map[rune]string{'Æ':"AE",'Ð':"D",'Ł':"L",'Ø':"OE",'Þ':"Th",'ß':"ss",'æ':"ae",'ð':"d",'ł':"l",'ø':"oe",'þ':"th",'Œ':"OE",'œ':"oe"} 
func RemoveAccents(s string) string { 
    b := make([]byte, len(s)) 
    t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC) 
    _, _, e := t.Transform(b, []byte(s), true) 
    if e != nil { panic(e) } 
    r := string(b) 

    var f bytes.Buffer 
    for _, c := range r { 
     temp := rune(c) 
     if val, ok := transliterations[temp]; ok { 
      f.WriteString(val) 
     } else { 
      f.WriteRune(temp) 
     } 
    } 
    return f.String() 
} 

Vì vậy, tôi bắt đầu với một chuỗi bởi vì đó là những gì tôi nhận được, sau đó tôi chuyển đổi nó thành một mảng byte, sau đó trở lại một chuỗi, sau đó đến một mảng byte một lần nữa, sau đó trở lại một chuỗi một lần nữa. Chắc chắn điều này là không cần thiết nhưng tôi không thể tìm ra cách để không làm điều này ..? Và nó thực sự có rất nhiều chi phí hay tôi không phải lo lắng về việc làm chậm mọi thứ với chuyển đổi quá mức?

(Ngoài ra nếu có ai có thời gian tôi chưa tìm ra cách bytes.Buffer thực sự hoạt động, sẽ không tốt hơn nếu khởi tạo bộ đệm có kích thước 2x của chuỗi, là kích thước đầu ra tối đa của giá trị trả về ?)

Trả lời

3

Trong Go, string s không đổi nên bất kỳ thay đổi nào cũng tạo ra chuỗi mới. Theo nguyên tắc chung, hãy chuyển đổi từ một số string thành một số byte hoặc rune một lần và chuyển đổi lại thành một lần string một lần. Để tránh phân bổ lại, cho phân bổ nhỏ và tạm thời, phân bổ quá mức để cung cấp một mức độ an toàn nếu bạn không biết chính xác số.

Ví dụ,

package main 

import (
    "bytes" 
    "fmt" 
    "unicode" 
    "unicode/utf8" 

    "code.google.com/p/go.text/transform" 
    "code.google.com/p/go.text/unicode/norm" 
) 

var isMn = func(r rune) bool { 
    return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks 
} 

var transliterations = map[rune]string{ 
    'Æ': "AE", 'Ð': "D", 'Ł': "L", 'Ø': "OE", 'Þ': "Th", 
    'ß': "ss", 'æ': "ae", 'ð': "d", 'ł': "l", 'ø': "oe", 
    'þ': "th", 'Œ': "OE", 'œ': "oe", 
} 

func RemoveAccents(b []byte) ([]byte, error) { 
    mnBuf := make([]byte, len(b)*125/100) 
    t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC) 
    n, _, err := t.Transform(mnBuf, b, true) 
    if err != nil { 
     return nil, err 
    } 
    mnBuf = mnBuf[:n] 
    tlBuf := bytes.NewBuffer(make([]byte, 0, len(mnBuf)*125/100)) 
    for i, w := 0, 0; i < len(mnBuf); i += w { 
     r, width := utf8.DecodeRune(mnBuf[i:]) 
     if s, ok := transliterations[r]; ok { 
      tlBuf.WriteString(s) 
     } else { 
      tlBuf.WriteRune(r) 
     } 
     w = width 
    } 
    return tlBuf.Bytes(), nil 
} 

func main() { 
    in := "test stringß" 
    fmt.Println(in) 
    inBytes := []byte(in) 
    outBytes, err := RemoveAccents(inBytes) 
    if err != nil { 
     fmt.Println(err) 
    } 
    out := string(outBytes) 
    fmt.Println(out) 
} 

Output:

test stringß 
test stringss 
+0

Ưa thích. 'Width' có vẻ không cần thiết ... tôi có thể không chỉ làm cho nó' r, w: = utf8.DecodeRune' và sau đó bỏ đi với 'w = width'? – Alasdair

+0

@Alasdair: Không. 'I, w: = 0, 0' khai báo' w' cho phạm vi bên ngoài. 'r, w: = utf8.DecodeRune' sẽ redeclare' w' cho phạm vi bên trong. 'i + = w' sử dụng' w' trong phạm vi bên ngoài, vì vậy bạn sẽ nhận được một lỗi "' w khai báo và không được sử dụng' "cho' w' trong phạm vi bên trong. [Đặc tả ngôn ngữ lập trình đi] (http://golang.org/ref/spec); [Blocks] (http://golang.org/ref/spec#Blocks); [Tuyên bố và phạm vi] (http://golang.org/ref/spec#Declarations_and_scope); [Khai báo biến ngắn] (http://golang.org/ref/spec#Short_variable_declarations). – peterSO

+0

Được rồi. Cảm ơn vì đã giải thích. – Alasdair

1

Có một chi phí nhỏ với chuyển đổi chuỗi thành byte slice (không phải mảng, đó là different type). Cụ thể phân bổ không gian cho lát byte.

Chuỗi là loại riêng và là cách diễn giải chuỗi byte. Nhưng không phải mọi chuỗi byte là một chuỗi hữu ích. Các chuỗi cũng là immutable. Nếu bạn nhìn vào số strings package, bạn sẽ thấy các chuỗi đó sẽ là sliced rất nhiều.

Trong ví dụ của bạn, bạn có thể bỏ qua chuyển đổi thứ hai trở lại chuỗi. Bạn cũng có thể trải rộng trên một lát byte.

Giống như mọi câu hỏi về hiệu suất: có thể bạn sẽ cần phải đo lường. Việc phân bổ các lát byte thực sự là nút cổ chai của bạn?

Bạn có thể khởi tạo bytes.Buffer bạn như vậy:

f := bytes.NewBuffer(make([]byte, 0, len(s)*2)) 

nơi bạn có kích thước từ 0 và công suất 2x kích thước của chuỗi của bạn. Nếu bạn có thể ước tính kích thước của bộ đệm của bạn, nó có lẽ là tốt để làm điều đó. Nó sẽ giúp bạn tiết kiệm một vài sự tái phân bổ của các lát byte cơ bản.

+0

Cảm ơn đã tư vấn về khởi tạo bộ đệm. Đối với phạm vi trên chuỗi, tôi nghĩ rằng nó cần phải là một chuỗi vì phạm vi trên chuỗi phạm vi của rune, đó là những gì tôi cần trong trường hợp đó. Nó có thể có thể được thực hiện với một máy quét trên mảng byte, nhưng tôi đã không học được cách để làm điều đó được nêu ra. – Alasdair

+0

@Alasdair, bạn có thể nhận được rune từ một '[] byte' với' bufio.Reader.ReadRune', hoặc trực tiếp hơn với chỉ 'utf8.DecodeRune'. – JimB

2

Không có câu trả lời cho câu hỏi này. Nếu những chuyển đổi này là một nút cổ chai hiệu suất trong ứng dụng của bạn, bạn nên sửa chúng. Nếu không: Không.

Bạn có hồ sơ ứng dụng của mình dưới tải thực tế và RemoveAccents là nút cổ chai không? Không? Vậy tại sao lại bận tâm?

Thực sự: Tôi cho rằng người ta có thể làm tốt hơn (theo nghĩa là ít rác hơn, ít lặp lại và ít chuyển đổi hơn), ví dụ: bằng cách chuỗi trong một số "TransliterationTransformer". Nhưng tôi nghi ngờ nó sẽ là sự phiền phức.

+2

Vâng ... Tôi hiểu những gì bạn đang nói, nhưng tôi muốn có một ý tưởng trong đầu của tôi về hiệu quả của phong cách mã hóa của tôi. Đó là một câu hỏi của thói quen để đi vào chứ không phải là hồ sơ và tối ưu hóa các ứng dụng cụ thể. – Alasdair

Các vấn đề liên quan