需求
- 需要讲字符串中的非数字转为
*
,单个汉子对应一个*
。 - 例如 我12ab1c -->
*
12**
1*
实现
错误实现一
- 假如相邻的
**
需要合并成*
func StrNotNumberToStar(str string) string {
b := []byte(str)
for i, v := range b {
if v > '9' || v < '0' {
b[i] = '*'
}
}
strReplaceBefore := string(b)
strRet := string(b)
for {
if strings.Contains(strRet, "**") {
strRet = strings.ReplaceAll(strRet, "**", "*")
} else {
break
}
}
return strRet
}
错误实现二
错误实现一采用了递归,效率相对较慢,下面是非递归的方式
func StrNotNumberToStar(str string) string {
b := []byte(str)
for i, v := range b {
if v > '9' || v < '0' {
b[i] = '*'
}
}
b2 := make([]byte, 0)
bPre := false // 上一个是*
for _, v := range b {
if v != '*' {
b2 = append(b2, v)
bPre = false
} else if !bPre {
b2 = append(b2, '*')
bPre = true
}
}
fmt.Printf("非递归 %+v \n", string(b2))
return string(b2)
}
正确实现
以上实现不合需求,需要另辟蹊径。
已知 utf8.RuneCountInString(“1一e”) =3,即utf8.RuneCountInString 返回结果认定中文、数字、字母都是一个单位。查阅 utf8.RuneCountInString 源码,做一定修改可得
const (
RuneSelf = 0x80 // characters below RuneSelf are represented as themselves in a single byte.
)
const (
// The default lowest and highest continuation byte.
locb = 0b10000000
hicb = 0b10111111
// These names of these constants are chosen to give nice alignment in the
// table below. The first nibble is an index into acceptRanges or F for
// special one-byte cases. The second nibble is the Rune length or the
// Status for the special one-byte case.
xx = 0xF1 // invalid: size 1
as = 0xF0 // ASCII: size 1
s1 = 0x02 // accept 0, size 2
s2 = 0x13 // accept 1, size 3
s3 = 0x03 // accept 0, size 3
s4 = 0x23 // accept 2, size 3
s5 = 0x34 // accept 3, size 4
s6 = 0x04 // accept 0, size 4
s7 = 0x44 // accept 4, size 4
)
var first = [256]uint8{
// 1 2 3 4 5 6 7 8 9 A B C D E F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x00-0x0F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x10-0x1F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x20-0x2F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x30-0x3F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x40-0x4F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x50-0x5F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x60-0x6F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x70-0x7F
// 1 2 3 4 5 6 7 8 9 A B C D E F
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x80-0x8F
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x90-0x9F
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xA0-0xAF
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xB0-0xBF
xx, xx, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xC0-0xCF
s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xD0-0xDF
s2, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s4, s3, s3, // 0xE0-0xEF
s5, s6, s6, s6, s7, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xF0-0xFF
}
var acceptRanges = [16]acceptRange{
0: {locb, hicb},
1: {0xA0, hicb},
2: {locb, 0x9F},
3: {0x90, hicb},
4: {locb, 0x8F},
}
type acceptRange struct {
lo uint8 // lowest value for second byte.
hi uint8 // highest value for second byte.
}
func RuneCountInString(s string) (n int) {
ns := len(s)
for i := 0; i < ns; n++ {
c := s[i]
if c < RuneSelf {
// ASCII fast path
i++
continue
}
x := first[c]
if x == xx {
i++ // invalid.
continue
}
size := int(x & 7)
if i+size > ns {
i++ // Short or invalid.
continue
}
accept := acceptRanges[x>>4]
if c := s[i+1]; c < accept.lo || accept.hi < c {
size = 1
} else if size == 2 {
} else if c := s[i+2]; c < locb || hicb < c {
size = 1
} else if size == 3 {
} else if c := s[i+3]; c < locb || hicb < c {
size = 1
}
i += size
}
return n
}
func StrNotNumberToStar2(s string) string {
bs := make([]byte, 0)
AddToBs := func(b byte) {
if b >= '0' && b <= '9' {
bs = append(bs, b)
} else {
bs = append(bs, '*')
}
}
n := 0
ns := len(s)
for i := 0; i < ns; n++ {
c := s[i]
if c < RuneSelf {
// ASCII fast path
i++
AddToBs(c)
continue
}
x := first[c]
if x == xx {
i++ // invalid.
AddToBs(c)
continue
}
size := int(x & 7)
if i+size > ns {
i++ // Short or invalid.
AddToBs(c)
continue
}
accept := acceptRanges[x>>4]
if c := s[i+1]; c < accept.lo || accept.hi < c {
size = 1
} else if size == 2 {
} else if c := s[i+2]; c < locb || hicb < c {
size = 1
} else if size == 3 {
} else if c := s[i+3]; c < locb || hicb < c {
size = 1
}
i += size
AddToBs(c)
}
return string(bs)
}