github.com/seeker-insurance/kit@v0.0.13/str/str.go (about)

     1  //Package str contains various tools for manipulation of strings beyond those available in golang's `strings` library. it also conatains a wide variety of string constants.
     2  package str
     3  
     4  import (
     5  	"bytes"
     6  	"fmt"
     7  	"strings"
     8  
     9  	"github.com/seeker-insurance/kit/runeset"
    10  )
    11  
    12  //RemoveRunes removes any runes listed from the string.
    13  //Note that this converts to runes and back to UTF-8, so RemoveRunes(s) == s
    14  //does not necessarially hold, since the code points may differ.
    15  func RemoveRunes(s string, toRemove ...rune) string {
    16  	buf := bytes.Buffer{}
    17  	set := runeset.FromRunes(toRemove...)
    18  	for _, r := range s {
    19  		if !set.Contains(r) {
    20  			buf.WriteRune(r)
    21  		}
    22  	}
    23  	return buf.String()
    24  }
    25  
    26  //RemoveWhiteSpace is an alias for RemoveASCIIWhiteSpace.
    27  var RemoveWhiteSpace = RemoveASCIIWhiteSpace
    28  
    29  //RuneDiff represents a difference in runes between two []rune.
    30  type RuneDiff struct {
    31  	a, b     rune
    32  	position int
    33  }
    34  
    35  func (rd RuneDiff) String() string {
    36  	return fmt.Sprintf(`(%s, %s)`, subIfNoChar(rd.a), subIfNoChar(rd.b))
    37  }
    38  
    39  func subIfNoChar(r rune) string {
    40  	if r == noChar {
    41  		return "NO_CHAR"
    42  	}
    43  	return string(r)
    44  }
    45  
    46  //Diffs represents a difference in runes between strings.
    47  type Diffs []RuneDiff
    48  
    49  func (d Diffs) String() string {
    50  	strs := make([]string, len(d))
    51  	for i, rd := range d {
    52  		strs[i] = rd.String()
    53  	}
    54  	return fmt.Sprintf("[%s]", strings.Join(strs, ", "))
    55  
    56  }
    57  
    58  //noCharacter is an code point from the unicode private use block which we use to represent one part of a diff having no character.
    59  const noChar rune = '\uE011'
    60  
    61  //RuneDiff returns a list of the differing rune-pairs in a string
    62  func runeDiff(s, q []rune) Diffs {
    63  	var diffs Diffs
    64  	short := min(len(s), len(q))
    65  	for i := 0; i < short; i++ {
    66  		c, d := s[i], q[i]
    67  		if c != d {
    68  			diffs = append(diffs, RuneDiff{c, d, i})
    69  		}
    70  	}
    71  	if len(s) == short {
    72  		for i, d := range q[short:] {
    73  			diffs = append(diffs, RuneDiff{a: noChar, b: d, position: short + i})
    74  		}
    75  	} else {
    76  		for i, c := range s[short:] {
    77  			diffs = append(diffs, RuneDiff{a: c, b: noChar, position: short + i})
    78  		}
    79  	}
    80  	return diffs
    81  }
    82  
    83  //Diff compares the runes in the string for differences. Call Diff.String() for a pretty-printed list.
    84  //Diff(a, b) == null if there is no difference.
    85  func Diff(a, b string) Diffs {
    86  	return runeDiff([]rune(a), []rune(b))
    87  }
    88  
    89  func min(a, b int) int {
    90  	if a < b {
    91  		return a
    92  	}
    93  	return b
    94  }
    95  
    96  //Map a function over a slice, returning a slice containing f(s) for s in a.
    97  func Map(f func(string) string, a []string) []string {
    98  	mapped := make([]string, len(a))
    99  	for i, s := range a {
   100  		mapped[i] = f(s)
   101  	}
   102  	return mapped
   103  }
   104  
   105  //Trim a string to n runes, adding a filler (if any) to show that it has been trimmed.
   106  func Trim(s string, n int, filler string) string {
   107  	r := []rune(s)
   108  	if len(r) <= n {
   109  		return s
   110  	}
   111  	return string(r[:n]) + filler
   112  }
   113  
   114  //ContainsAny returns true if strings.Contains(s, sub) is true for any sub in subStrs. ContainsAny(s) is false.
   115  func ContainsAny(s string, subStrs ...string) bool {
   116  	for _, sub := range subStrs {
   117  		if strings.Contains(s, sub) {
   118  			return true
   119  		}
   120  	}
   121  	return false
   122  }
   123  
   124  //ContainsAll returns true if strings.Contains(s, sub) is true for all sub in subStrs. ContainsAll(s) is true.
   125  func ContainsAll(s string, subStrs ...string) bool {
   126  	for _, sub := range subStrs {
   127  		if !strings.Contains(s, sub) {
   128  			return false
   129  		}
   130  	}
   131  	return true
   132  }