2016-02-02 22:03:37 +03:00
|
|
|
package runes
|
|
|
|
|
2018-02-16 17:36:02 +03:00
|
|
|
import (
|
|
|
|
"strings"
|
|
|
|
"unicode/utf8"
|
|
|
|
)
|
|
|
|
|
|
|
|
func Head(s string, r int) string {
|
|
|
|
var i, m int
|
|
|
|
for i < len(s) {
|
|
|
|
_, n := utf8.DecodeRuneInString(s[i:])
|
|
|
|
i += n
|
|
|
|
m += 1
|
|
|
|
if m == r {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return s[:i]
|
|
|
|
}
|
|
|
|
|
|
|
|
func Tail(s string, r int) string {
|
|
|
|
var i, n int
|
|
|
|
for i = len(s); i >= 0; {
|
|
|
|
var ok bool
|
|
|
|
for j := 1; j <= 4 && i-j >= 0; j++ {
|
|
|
|
v, _ := utf8.DecodeRuneInString(s[i-j:])
|
|
|
|
if v != utf8.RuneError {
|
|
|
|
i -= j
|
|
|
|
n++
|
|
|
|
ok = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !ok || n == r {
|
|
|
|
return s[i:]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return s[i:]
|
|
|
|
}
|
|
|
|
|
|
|
|
func ExactlyRunesCount(s string, n int) bool {
|
|
|
|
var m int
|
|
|
|
for range s {
|
|
|
|
m++
|
|
|
|
if m > n {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return m == n
|
|
|
|
}
|
|
|
|
|
|
|
|
func AtLeastRunesCount(s string, n int) bool {
|
|
|
|
var m int
|
|
|
|
for range s {
|
|
|
|
m++
|
|
|
|
if m >= n {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func IndexAnyRune(s string, rs []rune) int {
|
|
|
|
for _, r := range rs {
|
|
|
|
if i := strings.IndexRune(s, r); i != -1 {
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
func LastIndexAnyRune(s string, rs []rune) int {
|
|
|
|
for _, r := range rs {
|
|
|
|
i := -1
|
|
|
|
if 0 <= r && r < utf8.RuneSelf {
|
|
|
|
i = strings.LastIndexByte(s, byte(r))
|
|
|
|
} else {
|
|
|
|
sub := s
|
|
|
|
for len(sub) > 0 {
|
|
|
|
j := strings.IndexRune(s, r)
|
|
|
|
if j == -1 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
i = j
|
|
|
|
sub = sub[i+1:]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if i != -1 {
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
2016-02-02 22:03:37 +03:00
|
|
|
func Index(s, needle []rune) int {
|
|
|
|
ls, ln := len(s), len(needle)
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case ln == 0:
|
|
|
|
return 0
|
|
|
|
case ln == 1:
|
|
|
|
return IndexRune(s, needle[0])
|
|
|
|
case ln == ls:
|
|
|
|
if Equal(s, needle) {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return -1
|
|
|
|
case ln > ls:
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
head:
|
|
|
|
for i := 0; i < ls && ls-i >= ln; i++ {
|
|
|
|
for y := 0; y < ln; y++ {
|
|
|
|
if s[i+y] != needle[y] {
|
|
|
|
continue head
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
func LastIndex(s, needle []rune) int {
|
|
|
|
ls, ln := len(s), len(needle)
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case ln == 0:
|
|
|
|
if ls == 0 {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return ls
|
|
|
|
case ln == 1:
|
|
|
|
return IndexLastRune(s, needle[0])
|
|
|
|
case ln == ls:
|
|
|
|
if Equal(s, needle) {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return -1
|
|
|
|
case ln > ls:
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
head:
|
|
|
|
for i := ls - 1; i >= 0 && i >= ln; i-- {
|
|
|
|
for y := ln - 1; y >= 0; y-- {
|
|
|
|
if s[i-(ln-y-1)] != needle[y] {
|
|
|
|
continue head
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return i - ln + 1
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
// IndexAny returns the index of the first instance of any Unicode code point
|
|
|
|
// from chars in s, or -1 if no Unicode code point from chars is present in s.
|
|
|
|
func IndexAny(s, chars []rune) int {
|
|
|
|
if len(chars) > 0 {
|
|
|
|
for i, c := range s {
|
|
|
|
for _, m := range chars {
|
|
|
|
if c == m {
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
func Contains(s, needle []rune) bool {
|
|
|
|
return Index(s, needle) >= 0
|
|
|
|
}
|
|
|
|
|
2016-02-23 14:46:20 +03:00
|
|
|
func Max(s []rune) (max rune) {
|
|
|
|
for _, r := range s {
|
|
|
|
if r > max {
|
|
|
|
max = r
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func Min(s []rune) rune {
|
|
|
|
min := rune(-1)
|
|
|
|
for _, r := range s {
|
|
|
|
if min == -1 {
|
|
|
|
min = r
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if r < min {
|
|
|
|
min = r
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return min
|
|
|
|
}
|
|
|
|
|
2016-02-02 22:03:37 +03:00
|
|
|
func IndexRune(s []rune, r rune) int {
|
|
|
|
for i, c := range s {
|
|
|
|
if c == r {
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
func IndexLastRune(s []rune, r rune) int {
|
|
|
|
for i := len(s) - 1; i >= 0; i-- {
|
|
|
|
if s[i] == r {
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
func Equal(a, b []rune) bool {
|
2018-02-16 17:36:02 +03:00
|
|
|
// TODO use bytes.Equal with unsafe.
|
2016-02-02 22:03:37 +03:00
|
|
|
if len(a) == len(b) {
|
|
|
|
for i := 0; i < len(a); i++ {
|
|
|
|
if a[i] != b[i] {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// HasPrefix tests whether the string s begins with prefix.
|
|
|
|
func HasPrefix(s, prefix []rune) bool {
|
|
|
|
return len(s) >= len(prefix) && Equal(s[0:len(prefix)], prefix)
|
|
|
|
}
|
|
|
|
|
|
|
|
// HasSuffix tests whether the string s ends with suffix.
|
|
|
|
func HasSuffix(s, suffix []rune) bool {
|
|
|
|
return len(s) >= len(suffix) && Equal(s[len(s)-len(suffix):], suffix)
|
|
|
|
}
|