glob/util/runes/runes.go

249 lines
3.6 KiB
Go
Raw Permalink Normal View History

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)
}