Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
strings.go1292 linesDownload Raw Back to strings
1// Copyright 2009 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5// Package strings implements simple functions to manipulate UTF-8 encoded strings.6//7// For information about UTF-8 strings in Go, see https://blog.golang.org/strings.8package strings9 10import (11	"internal/bytealg"12	"internal/stringslite"13	"math/bits"14	"unicode"15	"unicode/utf8"16)17 18const maxInt = int(^uint(0) >> 1)19 20// explode splits s into a slice of UTF-8 strings,21// one string per Unicode character up to a maximum of n (n < 0 means no limit).22// Invalid UTF-8 bytes are sliced individually.23func explode(s string, n int) []string {24	l := utf8.RuneCountInString(s)25	if n < 0 || n > l {26		n = l27	}28	a := make([]string, n)29	for i := 0; i < n-1; i++ {30		_, size := utf8.DecodeRuneInString(s)31		a[i] = s[:size]32		s = s[size:]33	}34	if n > 0 {35		a[n-1] = s36	}37	return a38}39 40// Count counts the number of non-overlapping instances of substr in s.41// If substr is an empty string, Count returns 1 + the number of Unicode code points in s.42func Count(s, substr string) int {43	// special case44	if len(substr) == 0 {45		return utf8.RuneCountInString(s) + 146	}47	if len(substr) == 1 {48		return bytealg.CountString(s, substr[0])49	}50	n := 051	for {52		i := Index(s, substr)53		if i == -1 {54			return n55		}56		n++57		s = s[i+len(substr):]58	}59}60 61// Contains reports whether substr is within s.62func Contains(s, substr string) bool {63	return Index(s, substr) >= 064}65 66// ContainsAny reports whether any Unicode code points in chars are within s.67func ContainsAny(s, chars string) bool {68	return IndexAny(s, chars) >= 069}70 71// ContainsRune reports whether the Unicode code point r is within s.72func ContainsRune(s string, r rune) bool {73	return IndexRune(s, r) >= 074}75 76// ContainsFunc reports whether any Unicode code points r within s satisfy f(r).77func ContainsFunc(s string, f func(rune) bool) bool {78	return IndexFunc(s, f) >= 079}80 81// LastIndex returns the index of the last instance of substr in s, or -1 if substr is not present in s.82func LastIndex(s, substr string) int {83	n := len(substr)84	switch {85	case n == 0:86		return len(s)87	case n == 1:88		return bytealg.LastIndexByteString(s, substr[0])89	case n == len(s):90		if substr == s {91			return 092		}93		return -194	case n > len(s):95		return -196	}97	// Rabin-Karp search from the end of the string98	hashss, pow := bytealg.HashStrRev(substr)99	last := len(s) - n100	var h uint32101	for i := len(s) - 1; i >= last; i-- {102		h = h*bytealg.PrimeRK + uint32(s[i])103	}104	if h == hashss && s[last:] == substr {105		return last106	}107	for i := last - 1; i >= 0; i-- {108		h *= bytealg.PrimeRK109		h += uint32(s[i])110		h -= pow * uint32(s[i+n])111		if h == hashss && s[i:i+n] == substr {112			return i113		}114	}115	return -1116}117 118// IndexByte returns the index of the first instance of c in s, or -1 if c is not present in s.119func IndexByte(s string, c byte) int {120	return stringslite.IndexByte(s, c)121}122 123// IndexRune returns the index of the first instance of the Unicode code point124// r, or -1 if rune is not present in s.125// If r is [utf8.RuneError], it returns the first instance of any126// invalid UTF-8 byte sequence.127func IndexRune(s string, r rune) int {128	const haveFastIndex = bytealg.MaxBruteForce > 0129	switch {130	case 0 <= r && r < utf8.RuneSelf:131		return IndexByte(s, byte(r))132	case r == utf8.RuneError:133		for i, r := range s {134			if r == utf8.RuneError {135				return i136			}137		}138		return -1139	case !utf8.ValidRune(r):140		return -1141	default:142		// Search for rune r using the last byte of its UTF-8 encoded form.143		// The distribution of the last byte is more uniform compared to the144		// first byte which has a 78% chance of being [240, 243, 244].145		rs := string(r)146		last := len(rs) - 1147		i := last148		fails := 0149		for i < len(s) {150			if s[i] != rs[last] {151				o := IndexByte(s[i+1:], rs[last])152				if o < 0 {153					return -1154				}155				i += o + 1156			}157			// Step backwards comparing bytes.158			for j := 1; j < len(rs); j++ {159				if s[i-j] != rs[last-j] {160					goto next161				}162			}163			return i - last164		next:165			fails++166			i++167			if (haveFastIndex && fails > bytealg.Cutover(i)) && i < len(s) ||168				(!haveFastIndex && fails >= 4+i>>4 && i < len(s)) {169				goto fallback170			}171		}172		return -1173 174	fallback:175		// see comment in ../bytes/bytes.go176		if haveFastIndex {177			if j := bytealg.IndexString(s[i-last:], string(r)); j >= 0 {178				return i + j - last179			}180		} else {181			c0 := rs[last]182			c1 := rs[last-1]183		loop:184			for ; i < len(s); i++ {185				if s[i] == c0 && s[i-1] == c1 {186					for k := 2; k < len(rs); k++ {187						if s[i-k] != rs[last-k] {188							continue loop189						}190					}191					return i - last192				}193			}194		}195		return -1196	}197}198 199// IndexAny returns the index of the first instance of any Unicode code point200// from chars in s, or -1 if no Unicode code point from chars is present in s.201func IndexAny(s, chars string) int {202	if chars == "" {203		// Avoid scanning all of s.204		return -1205	}206	if len(chars) == 1 {207		// Avoid scanning all of s.208		r := rune(chars[0])209		if r >= utf8.RuneSelf {210			r = utf8.RuneError211		}212		return IndexRune(s, r)213	}214	if len(s) > 8 {215		if as, isASCII := makeASCIISet(chars); isASCII {216			for i := 0; i < len(s); i++ {217				if as.contains(s[i]) {218					return i219				}220			}221			return -1222		}223	}224	for i, c := range s {225		if IndexRune(chars, c) >= 0 {226			return i227		}228	}229	return -1230}231 232// LastIndexAny returns the index of the last instance of any Unicode code233// point from chars in s, or -1 if no Unicode code point from chars is234// present in s.235func LastIndexAny(s, chars string) int {236	if chars == "" {237		// Avoid scanning all of s.238		return -1239	}240	if len(s) == 1 {241		rc := rune(s[0])242		if rc >= utf8.RuneSelf {243			rc = utf8.RuneError244		}245		if IndexRune(chars, rc) >= 0 {246			return 0247		}248		return -1249	}250	if len(s) > 8 {251		if as, isASCII := makeASCIISet(chars); isASCII {252			for i := len(s) - 1; i >= 0; i-- {253				if as.contains(s[i]) {254					return i255				}256			}257			return -1258		}259	}260	if len(chars) == 1 {261		rc := rune(chars[0])262		if rc >= utf8.RuneSelf {263			rc = utf8.RuneError264		}265		for i := len(s); i > 0; {266			r, size := utf8.DecodeLastRuneInString(s[:i])267			i -= size268			if rc == r {269				return i270			}271		}272		return -1273	}274	for i := len(s); i > 0; {275		r, size := utf8.DecodeLastRuneInString(s[:i])276		i -= size277		if IndexRune(chars, r) >= 0 {278			return i279		}280	}281	return -1282}283 284// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s.285func LastIndexByte(s string, c byte) int {286	return bytealg.LastIndexByteString(s, c)287}288 289// Generic split: splits after each instance of sep,290// including sepSave bytes of sep in the subarrays.291func genSplit(s, sep string, sepSave, n int) []string {292	if n == 0 {293		return nil294	}295	if sep == "" {296		return explode(s, n)297	}298	if n < 0 {299		n = Count(s, sep) + 1300	}301 302	if n > len(s)+1 {303		n = len(s) + 1304	}305	a := make([]string, n)306	n--307	i := 0308	for i < n {309		m := Index(s, sep)310		if m < 0 {311			break312		}313		a[i] = s[:m+sepSave]314		s = s[m+len(sep):]315		i++316	}317	a[i] = s318	return a[:i+1]319}320 321// SplitN slices s into substrings separated by sep and returns a slice of322// the substrings between those separators.323//324// The count determines the number of substrings to return:325//   - n > 0: at most n substrings; the last substring will be the unsplit remainder;326//   - n == 0: the result is nil (zero substrings);327//   - n < 0: all substrings.328//329// Edge cases for s and sep (for example, empty strings) are handled330// as described in the documentation for [Split].331//332// To split around the first instance of a separator, see [Cut].333func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }334 335// SplitAfterN slices s into substrings after each instance of sep and336// returns a slice of those substrings.337//338// The count determines the number of substrings to return:339//   - n > 0: at most n substrings; the last substring will be the unsplit remainder;340//   - n == 0: the result is nil (zero substrings);341//   - n < 0: all substrings.342//343// Edge cases for s and sep (for example, empty strings) are handled344// as described in the documentation for [SplitAfter].345func SplitAfterN(s, sep string, n int) []string {346	return genSplit(s, sep, len(sep), n)347}348 349// Split slices s into all substrings separated by sep and returns a slice of350// the substrings between those separators.351//352// If s does not contain sep and sep is not empty, Split returns a353// slice of length 1 whose only element is s.354//355// If sep is empty, Split splits after each UTF-8 sequence. If both s356// and sep are empty, Split returns an empty slice.357//358// It is equivalent to [SplitN] with a count of -1.359//360// To split around the first instance of a separator, see [Cut].361func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) }362 363// SplitAfter slices s into all substrings after each instance of sep and364// returns a slice of those substrings.365//366// If s does not contain sep and sep is not empty, SplitAfter returns367// a slice of length 1 whose only element is s.368//369// If sep is empty, SplitAfter splits after each UTF-8 sequence. If370// both s and sep are empty, SplitAfter returns an empty slice.371//372// It is equivalent to [SplitAfterN] with a count of -1.373func SplitAfter(s, sep string) []string {374	return genSplit(s, sep, len(sep), -1)375}376 377var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1}378 379// Fields splits the string s around each instance of one or more consecutive white space380// characters, as defined by [unicode.IsSpace], returning a slice of substrings of s or an381// empty slice if s contains only white space. Every element of the returned slice is382// non-empty. Unlike [Split], leading and trailing runs of white space characters383// are discarded.384func Fields(s string) []string {385	// First count the fields.386	// This is an exact count if s is ASCII, otherwise it is an approximation.387	n := 0388	wasSpace := 1389	// setBits is used to track which bits are set in the bytes of s.390	setBits := uint8(0)391	for i := 0; i < len(s); i++ {392		r := s[i]393		setBits |= r394		isSpace := int(asciiSpace[r])395		n += wasSpace & ^isSpace396		wasSpace = isSpace397	}398 399	if setBits >= utf8.RuneSelf {400		// Some runes in the input string are not ASCII.401		return FieldsFunc(s, unicode.IsSpace)402	}403	// ASCII fast path404	a := make([]string, n)405	na := 0406	fieldStart := 0407	i := 0408	// Skip spaces in the front of the input.409	for i < len(s) && asciiSpace[s[i]] != 0 {410		i++411	}412	fieldStart = i413	for i < len(s) {414		if asciiSpace[s[i]] == 0 {415			i++416			continue417		}418		a[na] = s[fieldStart:i]419		na++420		i++421		// Skip spaces in between fields.422		for i < len(s) && asciiSpace[s[i]] != 0 {423			i++424		}425		fieldStart = i426	}427	if fieldStart < len(s) { // Last field might end at EOF.428		a[na] = s[fieldStart:]429	}430	return a431}432 433// FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c)434// and returns an array of slices of s. If all code points in s satisfy f(c) or the435// string is empty, an empty slice is returned. Every element of the returned slice is436// non-empty. Unlike [Split], leading and trailing runs of code points satisfying f(c)437// are discarded.438//439// FieldsFunc makes no guarantees about the order in which it calls f(c)440// and assumes that f always returns the same value for a given c.441func FieldsFunc(s string, f func(rune) bool) []string {442	// A span is used to record a slice of s of the form s[start:end].443	// The start index is inclusive and the end index is exclusive.444	type span struct {445		start int446		end   int447	}448	spans := make([]span, 0, 32)449 450	// Find the field start and end indices.451	// Doing this in a separate pass (rather than slicing the string s452	// and collecting the result substrings right away) is significantly453	// more efficient, possibly due to cache effects.454	start := -1 // valid span start if >= 0455	for end, rune := range s {456		if f(rune) {457			if start >= 0 {458				spans = append(spans, span{start, end})459				// Set start to a negative value.460				// Note: using -1 here consistently and reproducibly461				// slows down this code by a several percent on amd64.462				start = ^start463			}464		} else {465			if start < 0 {466				start = end467			}468		}469	}470 471	// Last field might end at EOF.472	if start >= 0 {473		spans = append(spans, span{start, len(s)})474	}475 476	// Create strings from recorded field indices.477	a := make([]string, len(spans))478	for i, span := range spans {479		a[i] = s[span.start:span.end]480	}481 482	return a483}484 485// Join concatenates the elements of its first argument to create a single string. The separator486// string sep is placed between elements in the resulting string.487func Join(elems []string, sep string) string {488	switch len(elems) {489	case 0:490		return ""491	case 1:492		return elems[0]493	}494 495	var n int496	if len(sep) > 0 {497		if len(sep) >= maxInt/(len(elems)-1) {498			panic("strings: Join output length overflow")499		}500		n += len(sep) * (len(elems) - 1)501	}502	for _, elem := range elems {503		if len(elem) > maxInt-n {504			panic("strings: Join output length overflow")505		}506		n += len(elem)507	}508 509	var b Builder510	b.Grow(n)511	b.WriteString(elems[0])512	for _, s := range elems[1:] {513		b.WriteString(sep)514		b.WriteString(s)515	}516	return b.String()517}518 519// HasPrefix reports whether the string s begins with prefix.520func HasPrefix(s, prefix string) bool {521	return stringslite.HasPrefix(s, prefix)522}523 524// HasSuffix reports whether the string s ends with suffix.525func HasSuffix(s, suffix string) bool {526	return stringslite.HasSuffix(s, suffix)527}528 529// Map returns a copy of the string s with all its characters modified530// according to the mapping function. If mapping returns a negative value, the character is531// dropped from the string with no replacement.532func Map(mapping func(rune) rune, s string) string {533	// In the worst case, the string can grow when mapped, making534	// things unpleasant. But it's so rare we barge in assuming it's535	// fine. It could also shrink but that falls out naturally.536 537	// The output buffer b is initialized on demand, the first538	// time a character differs.539	var b Builder540 541	for i, c := range s {542		r := mapping(c)543		if r == c && c != utf8.RuneError {544			continue545		}546 547		var width int548		if c == utf8.RuneError {549			c, width = utf8.DecodeRuneInString(s[i:])550			if width != 1 && r == c {551				continue552			}553		} else {554			width = utf8.RuneLen(c)555		}556 557		b.Grow(len(s) + utf8.UTFMax)558		b.WriteString(s[:i])559		if r >= 0 {560			b.WriteRune(r)561		}562 563		s = s[i+width:]564		break565	}566 567	// Fast path for unchanged input568	if b.Cap() == 0 { // didn't call b.Grow above569		return s570	}571 572	for _, c := range s {573		r := mapping(c)574 575		if r >= 0 {576			// common case577			// Due to inlining, it is more performant to determine if WriteByte should be578			// invoked rather than always call WriteRune579			if r < utf8.RuneSelf {580				b.WriteByte(byte(r))581			} else {582				// r is not an ASCII rune.583				b.WriteRune(r)584			}585		}586	}587 588	return b.String()589}590 591// According to static analysis, spaces, dashes, zeros, equals, and tabs592// are the most commonly repeated string literal,593// often used for display on fixed-width terminal windows.594// Pre-declare constants for these for O(1) repetition in the common-case.595const (596	repeatedSpaces = "" +597		"                                                                " +598		"                                                                "599	repeatedDashes = "" +600		"----------------------------------------------------------------" +601		"----------------------------------------------------------------"602	repeatedZeroes = "" +603		"0000000000000000000000000000000000000000000000000000000000000000"604	repeatedEquals = "" +605		"================================================================" +606		"================================================================"607	repeatedTabs = "" +608		"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" +609		"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"610)611 612// Repeat returns a new string consisting of count copies of the string s.613//614// It panics if count is negative or if the result of (len(s) * count)615// overflows.616func Repeat(s string, count int) string {617	switch count {618	case 0:619		return ""620	case 1:621		return s622	}623 624	// Since we cannot return an error on overflow,625	// we should panic if the repeat will generate an overflow.626	// See golang.org/issue/16237.627	if count < 0 {628		panic("strings: negative Repeat count")629	}630	hi, lo := bits.Mul(uint(len(s)), uint(count))631	if hi > 0 || lo > uint(maxInt) {632		panic("strings: Repeat output length overflow")633	}634	n := int(lo) // lo = len(s) * count635 636	if len(s) == 0 {637		return ""638	}639 640	// Optimize for commonly repeated strings of relatively short length.641	switch s[0] {642	case ' ', '-', '0', '=', '\t':643		switch {644		case n <= len(repeatedSpaces) && HasPrefix(repeatedSpaces, s):645			return repeatedSpaces[:n]646		case n <= len(repeatedDashes) && HasPrefix(repeatedDashes, s):647			return repeatedDashes[:n]648		case n <= len(repeatedZeroes) && HasPrefix(repeatedZeroes, s):649			return repeatedZeroes[:n]650		case n <= len(repeatedEquals) && HasPrefix(repeatedEquals, s):651			return repeatedEquals[:n]652		case n <= len(repeatedTabs) && HasPrefix(repeatedTabs, s):653			return repeatedTabs[:n]654		}655	}656 657	// Past a certain chunk size it is counterproductive to use658	// larger chunks as the source of the write, as when the source659	// is too large we are basically just thrashing the CPU D-cache.660	// So if the result length is larger than an empirically-found661	// limit (8KB), we stop growing the source string once the limit662	// is reached and keep reusing the same source string - that663	// should therefore be always resident in the L1 cache - until we664	// have completed the construction of the result.665	// This yields significant speedups (up to +100%) in cases where666	// the result length is large (roughly, over L2 cache size).667	const chunkLimit = 8 * 1024668	chunkMax := n669	if n > chunkLimit {670		chunkMax = chunkLimit / len(s) * len(s)671		if chunkMax == 0 {672			chunkMax = len(s)673		}674	}675 676	var b Builder677	b.Grow(n)678	b.WriteString(s)679	for b.Len() < n {680		chunk := min(n-b.Len(), b.Len(), chunkMax)681		b.WriteString(b.String()[:chunk])682	}683	return b.String()684}685 686// ToUpper returns s with all Unicode letters mapped to their upper case.687func ToUpper(s string) string {688	isASCII, hasLower := true, false689	for i := 0; i < len(s); i++ {690		c := s[i]691		if c >= utf8.RuneSelf {692			isASCII = false693			break694		}695		hasLower = hasLower || ('a' <= c && c <= 'z')696	}697 698	if isASCII { // optimize for ASCII-only strings.699		if !hasLower {700			return s701		}702		var (703			b   Builder704			pos int705		)706		b.Grow(len(s))707		for i := 0; i < len(s); i++ {708			c := s[i]709			if 'a' <= c && c <= 'z' {710				c -= 'a' - 'A'711				if pos < i {712					b.WriteString(s[pos:i])713				}714				b.WriteByte(c)715				pos = i + 1716			}717		}718		if pos < len(s) {719			b.WriteString(s[pos:])720		}721		return b.String()722	}723	return Map(unicode.ToUpper, s)724}725 726// ToLower returns s with all Unicode letters mapped to their lower case.727func ToLower(s string) string {728	isASCII, hasUpper := true, false729	for i := 0; i < len(s); i++ {730		c := s[i]731		if c >= utf8.RuneSelf {732			isASCII = false733			break734		}735		hasUpper = hasUpper || ('A' <= c && c <= 'Z')736	}737 738	if isASCII { // optimize for ASCII-only strings.739		if !hasUpper {740			return s741		}742		var (743			b   Builder744			pos int745		)746		b.Grow(len(s))747		for i := 0; i < len(s); i++ {748			c := s[i]749			if 'A' <= c && c <= 'Z' {750				c += 'a' - 'A'751				if pos < i {752					b.WriteString(s[pos:i])753				}754				b.WriteByte(c)755				pos = i + 1756			}757		}758		if pos < len(s) {759			b.WriteString(s[pos:])760		}761		return b.String()762	}763	return Map(unicode.ToLower, s)764}765 766// ToTitle returns a copy of the string s with all Unicode letters mapped to767// their Unicode title case.768func ToTitle(s string) string { return Map(unicode.ToTitle, s) }769 770// ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their771// upper case using the case mapping specified by c.772func ToUpperSpecial(c unicode.SpecialCase, s string) string {773	return Map(c.ToUpper, s)774}775 776// ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to their777// lower case using the case mapping specified by c.778func ToLowerSpecial(c unicode.SpecialCase, s string) string {779	return Map(c.ToLower, s)780}781 782// ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their783// Unicode title case, giving priority to the special casing rules.784func ToTitleSpecial(c unicode.SpecialCase, s string) string {785	return Map(c.ToTitle, s)786}787 788// ToValidUTF8 returns a copy of the string s with each run of invalid UTF-8 byte sequences789// replaced by the replacement string, which may be empty.790func ToValidUTF8(s, replacement string) string {791	var b Builder792 793	for i, c := range s {794		if c != utf8.RuneError {795			continue796		}797 798		_, wid := utf8.DecodeRuneInString(s[i:])799		if wid == 1 {800			b.Grow(len(s) + len(replacement))801			b.WriteString(s[:i])802			s = s[i:]803			break804		}805	}806 807	// Fast path for unchanged input808	if b.Cap() == 0 { // didn't call b.Grow above809		return s810	}811 812	invalid := false // previous byte was from an invalid UTF-8 sequence813	for i := 0; i < len(s); {814		c := s[i]815		if c < utf8.RuneSelf {816			i++817			invalid = false818			b.WriteByte(c)819			continue820		}821		_, wid := utf8.DecodeRuneInString(s[i:])822		if wid == 1 {823			i++824			if !invalid {825				invalid = true826				b.WriteString(replacement)827			}828			continue829		}830		invalid = false831		b.WriteString(s[i : i+wid])832		i += wid833	}834 835	return b.String()836}837 838// isSeparator reports whether the rune could mark a word boundary.839// TODO: update when package unicode captures more of the properties.840func isSeparator(r rune) bool {841	// ASCII alphanumerics and underscore are not separators842	if r <= 0x7F {843		switch {844		case '0' <= r && r <= '9':845			return false846		case 'a' <= r && r <= 'z':847			return false848		case 'A' <= r && r <= 'Z':849			return false850		case r == '_':851			return false852		}853		return true854	}855	// Letters and digits are not separators856	if unicode.IsLetter(r) || unicode.IsDigit(r) {857		return false858	}859	// Otherwise, all we can do for now is treat spaces as separators.860	return unicode.IsSpace(r)861}862 863// Title returns a copy of the string s with all Unicode letters that begin words864// mapped to their Unicode title case.865//866// Deprecated: The rule Title uses for word boundaries does not handle Unicode867// punctuation properly. Use golang.org/x/text/cases instead.868func Title(s string) string {869	// Use a closure here to remember state.870	// Hackish but effective. Depends on Map scanning in order and calling871	// the closure once per rune.872	prev := ' '873	return Map(874		func(r rune) rune {875			if isSeparator(prev) {876				prev = r877				return unicode.ToTitle(r)878			}879			prev = r880			return r881		},882		s)883}884 885// TrimLeftFunc returns a slice of the string s with all leading886// Unicode code points c satisfying f(c) removed.887func TrimLeftFunc(s string, f func(rune) bool) string {888	i := indexFunc(s, f, false)889	if i == -1 {890		return ""891	}892	return s[i:]893}894 895// TrimRightFunc returns a slice of the string s with all trailing896// Unicode code points c satisfying f(c) removed.897func TrimRightFunc(s string, f func(rune) bool) string {898	i := lastIndexFunc(s, f, false)899	if i >= 0 {900		_, wid := utf8.DecodeRuneInString(s[i:])901		i += wid902	} else {903		i++904	}905	return s[0:i]906}907 908// TrimFunc returns a slice of the string s with all leading909// and trailing Unicode code points c satisfying f(c) removed.910func TrimFunc(s string, f func(rune) bool) string {911	return TrimRightFunc(TrimLeftFunc(s, f), f)912}913 914// IndexFunc returns the index into s of the first Unicode915// code point satisfying f(c), or -1 if none do.916func IndexFunc(s string, f func(rune) bool) int {917	return indexFunc(s, f, true)918}919 920// LastIndexFunc returns the index into s of the last921// Unicode code point satisfying f(c), or -1 if none do.922func LastIndexFunc(s string, f func(rune) bool) int {923	return lastIndexFunc(s, f, true)924}925 926// indexFunc is the same as IndexFunc except that if927// truth==false, the sense of the predicate function is928// inverted.929func indexFunc(s string, f func(rune) bool, truth bool) int {930	for i, r := range s {931		if f(r) == truth {932			return i933		}934	}935	return -1936}937 938// lastIndexFunc is the same as LastIndexFunc except that if939// truth==false, the sense of the predicate function is940// inverted.941func lastIndexFunc(s string, f func(rune) bool, truth bool) int {942	for i := len(s); i > 0; {943		r, size := utf8.DecodeLastRuneInString(s[0:i])944		i -= size945		if f(r) == truth {946			return i947		}948	}949	return -1950}951 952// asciiSet is a 32-byte value, where each bit represents the presence of a953// given ASCII character in the set. The 128-bits of the lower 16 bytes,954// starting with the least-significant bit of the lowest word to the955// most-significant bit of the highest word, map to the full range of all956// 128 ASCII characters. The 128-bits of the upper 16 bytes will be zeroed,957// ensuring that any non-ASCII character will be reported as not in the set.958// This allocates a total of 32 bytes even though the upper half959// is unused to avoid bounds checks in asciiSet.contains.960type asciiSet [8]uint32961 962// makeASCIISet creates a set of ASCII characters and reports whether all963// characters in chars are ASCII.964func makeASCIISet(chars string) (as asciiSet, ok bool) {965	for i := 0; i < len(chars); i++ {966		c := chars[i]967		if c >= utf8.RuneSelf {968			return as, false969		}970		as[c/32] |= 1 << (c % 32)971	}972	return as, true973}974 975// contains reports whether c is inside the set.976func (as *asciiSet) contains(c byte) bool {977	return (as[c/32] & (1 << (c % 32))) != 0978}979 980// Trim returns a slice of the string s with all leading and981// trailing Unicode code points contained in cutset removed.982func Trim(s, cutset string) string {983	if s == "" || cutset == "" {984		return s985	}986	if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {987		return trimLeftByte(trimRightByte(s, cutset[0]), cutset[0])988	}989	if as, ok := makeASCIISet(cutset); ok {990		return trimLeftASCII(trimRightASCII(s, &as), &as)991	}992	return trimLeftUnicode(trimRightUnicode(s, cutset), cutset)993}994 995// TrimLeft returns a slice of the string s with all leading996// Unicode code points contained in cutset removed.997//998// To remove a prefix, use [TrimPrefix] instead.999func TrimLeft(s, cutset string) string {1000	if s == "" || cutset == "" {1001		return s1002	}1003	if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {1004		return trimLeftByte(s, cutset[0])1005	}1006	if as, ok := makeASCIISet(cutset); ok {1007		return trimLeftASCII(s, &as)1008	}1009	return trimLeftUnicode(s, cutset)1010}1011 1012func trimLeftByte(s string, c byte) string {1013	for len(s) > 0 && s[0] == c {1014		s = s[1:]1015	}1016	return s1017}1018 1019func trimLeftASCII(s string, as *asciiSet) string {1020	for len(s) > 0 {1021		if !as.contains(s[0]) {1022			break1023		}1024		s = s[1:]1025	}1026	return s1027}1028 1029func trimLeftUnicode(s, cutset string) string {1030	for len(s) > 0 {1031		r, n := utf8.DecodeRuneInString(s)1032		if !ContainsRune(cutset, r) {1033			break1034		}1035		s = s[n:]1036	}1037	return s1038}1039 1040// TrimRight returns a slice of the string s, with all trailing1041// Unicode code points contained in cutset removed.1042//1043// To remove a suffix, use [TrimSuffix] instead.1044func TrimRight(s, cutset string) string {1045	if s == "" || cutset == "" {1046		return s1047	}1048	if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {1049		return trimRightByte(s, cutset[0])1050	}1051	if as, ok := makeASCIISet(cutset); ok {1052		return trimRightASCII(s, &as)1053	}1054	return trimRightUnicode(s, cutset)1055}1056 1057func trimRightByte(s string, c byte) string {1058	for len(s) > 0 && s[len(s)-1] == c {1059		s = s[:len(s)-1]1060	}1061	return s1062}1063 1064func trimRightASCII(s string, as *asciiSet) string {1065	for len(s) > 0 {1066		if !as.contains(s[len(s)-1]) {1067			break1068		}1069		s = s[:len(s)-1]1070	}1071	return s1072}1073 1074func trimRightUnicode(s, cutset string) string {1075	for len(s) > 0 {1076		r, n := rune(s[len(s)-1]), 11077		if r >= utf8.RuneSelf {1078			r, n = utf8.DecodeLastRuneInString(s)1079		}1080		if !ContainsRune(cutset, r) {1081			break1082		}1083		s = s[:len(s)-n]1084	}1085	return s1086}1087 1088// TrimSpace returns a slice (substring) of the string s,1089// with all leading and trailing white space removed,1090// as defined by Unicode.1091func TrimSpace(s string) string {1092	// Fast path for ASCII: look for the first ASCII non-space byte.1093	for lo, c := range []byte(s) {1094		if c >= utf8.RuneSelf {1095			// If we run into a non-ASCII byte, fall back to the1096			// slower unicode-aware method on the remaining bytes.1097			return TrimFunc(s[lo:], unicode.IsSpace)1098		}1099		if asciiSpace[c] != 0 {1100			continue1101		}1102		s = s[lo:]1103		// Now look for the first ASCII non-space byte from the end.1104		for hi := len(s) - 1; hi >= 0; hi-- {1105			c := s[hi]1106			if c >= utf8.RuneSelf {1107				return TrimRightFunc(s[:hi+1], unicode.IsSpace)1108			}1109			if asciiSpace[c] == 0 {1110				// At this point, s[:hi+1] starts and ends with ASCII1111				// non-space bytes, so we're done. Non-ASCII cases have1112				// already been handled above.1113				return s[:hi+1]1114			}1115		}1116	}1117	return ""1118}1119 1120// TrimPrefix returns s without the provided leading prefix string.1121// If s doesn't start with prefix, s is returned unchanged.1122func TrimPrefix(s, prefix string) string {1123	return stringslite.TrimPrefix(s, prefix)1124}1125 1126// TrimSuffix returns s without the provided trailing suffix string.1127// If s doesn't end with suffix, s is returned unchanged.1128func TrimSuffix(s, suffix string) string {1129	return stringslite.TrimSuffix(s, suffix)1130}1131 1132// Replace returns a copy of the string s with the first n1133// non-overlapping instances of old replaced by new.1134// If old is empty, it matches at the beginning of the string1135// and after each UTF-8 sequence, yielding up to k+1 replacements1136// for a k-rune string.1137// If n < 0, there is no limit on the number of replacements.1138func Replace(s, old, new string, n int) string {1139	if old == new || n == 0 {1140		return s // avoid allocation1141	}1142 1143	// Compute number of replacements.1144	if m := Count(s, old); m == 0 {1145		return s // avoid allocation1146	} else if n < 0 || m < n {1147		n = m1148	}1149 1150	// Apply replacements to buffer.1151	var b Builder1152	b.Grow(len(s) + n*(len(new)-len(old)))1153	start := 01154	if len(old) > 0 {1155		for range n {1156			j := start + Index(s[start:], old)1157			b.WriteString(s[start:j])1158			b.WriteString(new)1159			start = j + len(old)1160		}1161	} else { // len(old) == 01162		b.WriteString(new)1163		for range n - 1 {1164			_, wid := utf8.DecodeRuneInString(s[start:])1165			j := start + wid1166			b.WriteString(s[start:j])1167			b.WriteString(new)1168			start = j1169		}1170	}1171	b.WriteString(s[start:])1172	return b.String()1173}1174 1175// ReplaceAll returns a copy of the string s with all1176// non-overlapping instances of old replaced by new.1177// If old is empty, it matches at the beginning of the string1178// and after each UTF-8 sequence, yielding up to k+1 replacements1179// for a k-rune string.1180func ReplaceAll(s, old, new string) string {1181	return Replace(s, old, new, -1)1182}1183 1184// EqualFold reports whether s and t, interpreted as UTF-8 strings,1185// are equal under simple Unicode case-folding, which is a more general1186// form of case-insensitivity.1187func EqualFold(s, t string) bool {1188	// ASCII fast path1189	i := 01190	for n := min(len(s), len(t)); i < n; i++ {1191		sr := s[i]1192		tr := t[i]1193		if sr|tr >= utf8.RuneSelf {1194			goto hasUnicode1195		}1196 1197		// Easy case.1198		if tr == sr {1199			continue1200		}

Showing the first 1,200 of 1292 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai