亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 golang 中正確拆分符文

在 golang 中正確拆分符文

Go
慕村225694 2022-07-04 16:12:50
我想知道是否有一種簡單的方法,例如處理代碼點/符文的眾所周知的函數,從符文片的中間取出一塊而不會弄亂它,或者是否都需要自己編碼才能下來等于或小于最大字節數。具體來說,我要做的是將字符串傳遞給函數,將其轉換為符文,以便我可以尊重代碼點,如果切片長于某些最大字節,則從符文中心移除足夠的符文以獲得字節到必要的。如果字符串只是單字節字符并且處理如下:這是簡單的數學運算:func shortenStringIDToMaxLength(in string, maxLen int) string {    if len(in) > maxLen {        excess := len(in) - maxLen        start := maxLen/2 - excess/2        return in[:start] + in[start+excess:]    }    return in}但是在一個可變字符寬度的字節字符串中,它要么需要更多的編碼循環,要么會有很好的函數來簡化它。有沒有人有關于如何最好地用符文處理這種事情的代碼示例?這里的想法是字符串將進入的 DB 字段具有固定的最大字節長度,而不是代碼點,因此需要一些從符文到最大字節的算法。從字符串中間取字符的原因只是這個特定程序的需要。謝謝!編輯:一旦我發現范圍運算符尊重字符串上的符文,這變得很容易只使用我發現的字符串,因為下面的答案很好。在這種情況下,我不必擔心字符串是格式良好的 UTF 格式,但如果我這樣做了,我現在知道 UTF 模塊,謝謝!這就是我最終得到的結果:package mainimport (    "fmt")func ShortenStringIDToMaxLength(in string, maxLen int) string {    if maxLen < 1 {        // Panic/log whatever is your error system of choice.    }    bytes := len(in)    if bytes > maxLen {        excess := bytes - maxLen        lPos := bytes/2 - excess/2        lastPos := 0        for pos, _ := range in {            if pos > lPos {                lPos = lastPos                break            }            lastPos = pos        }        rPos := lPos + excess        for pos, _ := range in[lPos:] {            if pos >= excess {                rPos = pos                break            }        }        return in[:lPos] + in[lPos+rPos:]    }    return in}func main() {    out := ShortenStringIDToMaxLength(`123456789 123456789`, 5)    fmt.Println(out, len(out))}https://play.golang.org/p/YLGlj_17A-j
查看完整描述

2 回答

?
胡子哥哥

TA貢獻1825條經驗 獲得超6個贊

這是您的算法的改編版,它從前綴的開頭和后綴的結尾刪除不完整的符文:


func TrimLastIncompleteRune(s string) string {

    l := len(s)


    for i := 1; i <= l; i++ {

        suff := s[l-i : l]

        // repeatedly try to decode a rune from the last bytes in string

        r, cnt := utf8.DecodeRuneInString(suff)

        if r == utf8.RuneError {

            continue

        }


        // if success : return the substring which contains

        // this succesfully decoded rune

        lgth := l - i + cnt

        return s[:lgth]

    }


    return ""

}


func TrimFirstIncompleteRune(s string) string {

    // repeatedly try to decode a rune from the beginning

    for i := 0; i < len(s); i++ {

        if r, _ := utf8.DecodeRuneInString(s[i:]); r != utf8.RuneError {

            // if success : return

            return s[i:]

        }

    }

    return ""

}


func shortenStringIDToMaxLength(in string, maxLen int) string {

    if len(in) > maxLen {

        firstHalf := maxLen / 2

        secondHalf := len(in) - (maxLen - firstHalf)


        prefix := TrimLastIncompleteRune(in[:firstHalf])

        suffix := TrimFirstIncompleteRune(in[secondHalf:])


        return prefix + suffix

    }

    return in

}

play.golang.org 上的鏈接


此算法僅嘗試從選定的前綴和后綴中刪除更多字節。


例如,如果事實證明您需要從后綴中刪除 3 個字節才能獲得有效的符文,則它不會嘗試查看是否可以在前綴中添加 3 個字節,以獲得更接近maxLen字節的最終結果。


查看完整回答
反對 回復 2022-07-04
?
冉冉說

TA貢獻1877條經驗 獲得超1個贊

您可以使用簡單的算術來查找start和end使得字符串s[:start]+s[end:]短于您的字節限制。但是您需要確保start和end都是任何 utf-8 序列的第一個字節,以保持序列有效。


UTF-8 的特性是任何給定字節都是序列的第一個字節,只要它的前兩位不是 10。


所以你可以寫這樣的代碼(操場: https: //play.golang.org/p/xk_Yo_1wTYc)


package main


import (

    "fmt"

)


func truncString(s string, maxLen int) string {

    if len(s) <= maxLen {

        return s

    }

    start := (maxLen + 1) / 2

    for start > 0 && s[start]>>6 == 0b10 {

        start--

    }

    end := len(s) - (maxLen - start)

    for end < len(s) && s[end]>>6 == 0b10 {

        end++

    }

    return s[:start] + s[end:]

}


func main() {

    fmt.Println(truncString("this is a test", 5))

    fmt.Println(truncString("日本語", 7))

}

無論輸入字符串有多長(假設它是有效的 utf-8),這段代碼都有一個理想的屬性,它需要 O(maxLen) 時間。


查看完整回答
反對 回復 2022-07-04
  • 2 回答
  • 0 關注
  • 138 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號