func Before(s, substr string) string {
	if !strings.Contains(s, substr) {
		return s
	}
	return s[:strings.Index(s, substr)]
}
Before returns part of the string before given substring
package strutil
import (
	"bytes"
	"strings"
)
var EllipsisSuffix = "..."
var defaultFieldsSeparators = []string{" ", "\t"}
func Concat(s ...string) string {
	var buffer bytes.Buffer
	for _, v := range s {
		buffer.WriteString(v)
	}
	return buffer.String()
}
func Substr(s string, start, length int) string {
	if s == "" || length <= 0 || start >= Len(s) {
		return ""
	}
	if start < 0 {
		start = 0
	}
	var count int
	var startIndex int
	for i := range s {
		if count == start {
			startIndex = i
		}
		if count-start == length {
			return s[startIndex:i]
		}
		count++
	}
	if startIndex != 0 {
		return s[startIndex:]
	}
	return s
}
func Substring(s string, start, end int) string {
	if s == "" || start == end || start >= Len(s) {
		return ""
	}
	if start < 0 {
		start = 0
	}
	if end < 0 {
		end = start
		start = 0
	}
	var count int
	var startIndex int
	for i := range s {
		if count == start {
			startIndex = i
		}
		if count == end {
			return s[startIndex:i]
		}
		count++
	}
	if startIndex != 0 {
		return s[startIndex:]
	}
	return s
}
func Extract(s string, start, end int) string {
	if s == "" || end < start {
		return ""
	}
	if start < 0 {
		start = 0
	}
	if end > len(s) {
		end = len(s)
	}
	return s[start:end]
}
func Len(s string) int {
	if s == "" {
		return 0
	}
	var count int
	for range s {
		count++
	}
	return count
}
func Ellipsis(s string, maxSize int) string {
	if Len(s) <= maxSize {
		return s
	}
	return Substr(s, 0, maxSize-Len(EllipsisSuffix)) + EllipsisSuffix
}
func Head(s string, n int) string {
	if s == "" || n <= 0 {
		return ""
	}
	l := Len(s)
	if l <= n {
		return s
	}
	return Substr(s, 0, n)
}
func Tail(s string, n int) string {
	if s == "" || n <= 0 {
		return ""
	}
	l := Len(s)
	if l <= n {
		return s
	}
	return Substr(s, l-n, l)
}
func PrefixSize(str string, prefix rune) int {
	if str == "" {
		return 0
	}
	var result int
	for i := 0; i < len(str); i++ {
		if rune(str[i]) != prefix {
			return result
		}
		result++
	}
	return result
}
func SuffixSize(str string, suffix rune) int {
	if str == "" {
		return 0
	}
	var result int
	for i := len(str) - 1; i >= 0; i-- {
		if rune(str[i]) != suffix {
			return result
		}
		result++
	}
	return result
}
func ReplaceAll(source, from, to string) string {
	if source == "" {
		return ""
	}
	var result strings.Builder
SOURCELOOP:
	for _, sourceSym := range source {
		for _, fromSym := range from {
			if fromSym == sourceSym {
				result.WriteString(to)
				continue SOURCELOOP
			}
		}
		result.WriteRune(sourceSym)
	}
	return result.String()
}
func Exclude(data, substr string) string {
	if len(data) == 0 || len(substr) == 0 {
		return data
	}
	return strings.ReplaceAll(data, substr, "")
}
func ReadField(data string, index int, multiSep bool, separators ...string) string {
	if data == "" || index < 0 {
		return ""
	}
	if len(separators) == 0 {
		separators = defaultFieldsSeparators
	}
	curIndex, startPointer := -1, -1
MAINLOOP:
	for i, r := range data {
		for _, s := range separators {
			if r == rune(s[0]) {
				if curIndex == index {
					return data[startPointer:i]
				}
				if !multiSep {
					startPointer = i + 1
					curIndex++
					continue MAINLOOP
				}
				startPointer = -1
				continue MAINLOOP
			}
		}
		if startPointer == -1 {
			startPointer = i
			curIndex++
		}
	}
	if index > curIndex {
		return ""
	}
	return data[startPointer:]
}
func Fields(data string) []string {
	var result []string
	var item strings.Builder
	var waitChar rune
	for _, char := range data {
		switch char {
		case '"', '\'', '`', '“', '”', '‘', '’', '«', '»', '„':
			if waitChar == 0 {
				waitChar = getClosingChar(char)
			} else if waitChar != 0 && waitChar == char {
				result = appendField(result, item.String())
				item.Reset()
				waitChar = 0
			} else {
				item.WriteRune(char)
			}
		case ',', ';', ' ':
			if waitChar != 0 {
				item.WriteRune(char)
			} else {
				result = appendField(result, item.String())
				item.Reset()
			}
		default:
			item.WriteRune(char)
		}
	}
	if item.Len() != 0 {
		result = appendField(result, item.String())
	}
	return result
}
func Copy(v string) string {
	return (v + " ")[:len(v)]
}