github.com/hoop33/elvish@v0.0.0-20160801152013-6d25485beab4/util/strings.go (about)

     1  package util
     2  
     3  import (
     4  	"errors"
     5  	"strings"
     6  )
     7  
     8  // ErrIndexOutOfRange is returned when out-of-range errors occur.
     9  var ErrIndexOutOfRange = errors.New("substring out of range")
    10  
    11  // FindContext takes a position in a text and finds its line number,
    12  // corresponding line and column numbers. Line and column numbers are counted
    13  // from 0. Used in diagnostic messages.
    14  func FindContext(text string, pos int) (lineno, colno int, line string) {
    15  	var i, linestart int
    16  	var r rune
    17  	for i, r = range text {
    18  		if i == pos {
    19  			break
    20  		}
    21  		if r == '\n' {
    22  			lineno++
    23  			linestart = i + 1
    24  			colno = 0
    25  		} else {
    26  			colno++
    27  		}
    28  	}
    29  	line = strings.SplitN(text[linestart:], "\n", 2)[0]
    30  	return
    31  }
    32  
    33  // FindFirstEOL returns the index of the first '\n'. When there is no '\n', the
    34  // length of s is returned.
    35  func FindFirstEOL(s string) int {
    36  	eol := strings.IndexRune(s, '\n')
    37  	if eol == -1 {
    38  		eol = len(s)
    39  	}
    40  	return eol
    41  }
    42  
    43  // FindLastSOL returns an index just after the last '\n'.
    44  func FindLastSOL(s string) int {
    45  	return strings.LastIndex(s, "\n") + 1
    46  }
    47  
    48  // SubstringByRune returns the range of the i-th rune (inclusive) through the
    49  // j-th rune (exclusive) in s.
    50  func SubstringByRune(s string, low, high int) (string, error) {
    51  	if low > high || low < 0 || high < 0 {
    52  		return "", ErrIndexOutOfRange
    53  	}
    54  	var bLow, bHigh, j int
    55  	for i := range s {
    56  		if j == low {
    57  			bLow = i
    58  		}
    59  		if j == high {
    60  			bHigh = i
    61  		}
    62  		j++
    63  	}
    64  	if j < high {
    65  		return "", ErrIndexOutOfRange
    66  	}
    67  	if low == high {
    68  		return "", nil
    69  	}
    70  	if j == high {
    71  		bHigh = len(s)
    72  	}
    73  	return s[bLow:bHigh], nil
    74  }
    75  
    76  // NthRune returns the n-th rune of s.
    77  func NthRune(s string, n int) (rune, error) {
    78  	if n < 0 {
    79  		return 0, ErrIndexOutOfRange
    80  	}
    81  	var j int
    82  	for _, r := range s {
    83  		if j == n {
    84  			return r, nil
    85  		}
    86  		j++
    87  	}
    88  	return 0, ErrIndexOutOfRange
    89  }
    90  
    91  // MatchSubseq returns whether pattern is a subsequence of s.
    92  func MatchSubseq(s, pattern string) bool {
    93  	for _, p := range pattern {
    94  		i := strings.IndexRune(s, p)
    95  		if i == -1 {
    96  			return false
    97  		}
    98  		s = s[i+len(string(p)):]
    99  	}
   100  	return true
   101  }