improve gstr.WordWrap

This commit is contained in:
John Guo 2022-05-13 14:18:51 +08:00
parent 6dccaf802c
commit 2680666f52
3 changed files with 62 additions and 23 deletions

View File

@ -9,12 +9,18 @@ package gstr
import (
"bytes"
"fmt"
"github.com/gogf/gf/v2/util/grand"
"math"
"regexp"
"strconv"
"strings"
"unicode"
"github.com/gogf/gf/v2/util/grand"
)
var (
// octReg is the regular expression object for checks octal string.
octReg = regexp.MustCompile(`\\[0-7]{3}`)
)
// Chr return the ascii string of a number(0-255).
@ -27,11 +33,6 @@ func Ord(char string) int {
return int(char[0])
}
var (
// octReg is the regular expression object for checks octal string.
octReg = regexp.MustCompile(`\\[0-7]{3}`)
)
// OctStr converts string container octal string to its original string,
// for example, to Chinese string.
// Eg: `\346\200\241` -> 怡
@ -175,7 +176,8 @@ func Nl2Br(str string, isXhtml ...bool) string {
}
// WordWrap wraps a string to a given number of characters.
// TODO: Enable cut parameter, see http://php.net/manual/en/function.wordwrap.php.
// This function supports cut parameters of both english and chinese punctuations.
// TODO: Enable custom cut parameter, see http://php.net/manual/en/function.wordwrap.php.
func WordWrap(str string, width int, br string) string {
if br == "" {
br = "\n"
@ -185,9 +187,11 @@ func WordWrap(str string, width int, br string) string {
wordBuf, spaceBuf bytes.Buffer
init = make([]byte, 0, len(str))
buf = bytes.NewBuffer(init)
strRunes = []rune(str)
)
for _, char := range []rune(str) {
if char == '\n' {
for _, char := range strRunes {
switch {
case char == '\n':
if wordBuf.Len() == 0 {
if current+spaceBuf.Len() > width {
current = 0
@ -205,7 +209,8 @@ func WordWrap(str string, width int, br string) string {
}
buf.WriteRune(char)
current = 0
} else if unicode.IsSpace(char) {
case unicode.IsSpace(char):
if spaceBuf.Len() == 0 || wordBuf.Len() > 0 {
current += spaceBuf.Len() + wordBuf.Len()
spaceBuf.WriteTo(buf)
@ -214,7 +219,18 @@ func WordWrap(str string, width int, br string) string {
wordBuf.Reset()
}
spaceBuf.WriteRune(char)
} else {
case isPunctuation(char):
wordBuf.WriteRune(char)
if spaceBuf.Len() == 0 || wordBuf.Len() > 0 {
current += spaceBuf.Len() + wordBuf.Len()
spaceBuf.WriteTo(buf)
spaceBuf.Reset()
wordBuf.WriteTo(buf)
wordBuf.Reset()
}
default:
wordBuf.WriteRune(char)
if current+spaceBuf.Len()+wordBuf.Len() > width && wordBuf.Len() < width {
buf.WriteString(br)
@ -234,3 +250,16 @@ func WordWrap(str string, width int, br string) string {
}
return buf.String()
}
func isPunctuation(char int32) bool {
switch char {
// English Punctuations.
case ';', '.', ',', ':', '~':
return true
// Chinese Punctuations.
case '', '', '。', '', '', '', '…', '、':
return true
default:
return false
}
}

View File

@ -4,8 +4,6 @@
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// go test *.go -bench=".*"
package gstr_test
import (
@ -20,3 +18,25 @@ func Test_OctStr(t *testing.T) {
t.Assert(gstr.OctStr(`\346\200\241`), "怡")
})
}
func Test_WordWrap(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
t.Assert(gstr.WordWrap("12 34", 2, "<br>"), "12<br>34")
t.Assert(gstr.WordWrap("12 34", 2, "\n"), "12\n34")
t.Assert(gstr.WordWrap("我爱 GF", 2, "\n"), "我爱\nGF")
t.Assert(gstr.WordWrap("A very long woooooooooooooooooord. and something", 7, "<br>"),
"A very<br>long<br>woooooooooooooooooord.<br>and<br>something")
})
// Chinese Punctuations.
gtest.C(t, func(t *gtest.T) {
var (
br = " "
content = " DelRouteKeyIPv6 删除VPC内的服务的Route信息;和DelRouteIPv6接口相比这个接口可以删除满足条件的多条RS\n"
length = 120
)
wrappedContent := gstr.WordWrap(content, length, "\n"+br)
t.Assert(wrappedContent, ` DelRouteKeyIPv6 删除VPC内的服务的Route信息;和DelRouteIPv6接口相比
这个接口可以删除满足条件的多条RS
`)
})
}

View File

@ -213,16 +213,6 @@ func Test_CountChars(t *testing.T) {
})
}
func Test_WordWrap(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
t.Assert(gstr.WordWrap("12 34", 2, "<br>"), "12<br>34")
t.Assert(gstr.WordWrap("12 34", 2, "\n"), "12\n34")
t.Assert(gstr.WordWrap("我爱 GF", 2, "\n"), "我爱\nGF")
t.Assert(gstr.WordWrap("A very long woooooooooooooooooord. and something", 7, "<br>"),
"A very<br>long<br>woooooooooooooooooord.<br>and<br>something")
})
}
func Test_LenRune(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
t.Assert(gstr.LenRune("1234"), 4)