v / vlib / strings / strings.v
147 lines · 142 sloc · 4.91 KB · 37255767290c243b71f0e78d77c3bd5e875748e6
Raw
1module strings
2
3// import rand
4// random returns a random string with `n` characters
5/*
6pub fn random(n int) string {
7 buf := vmalloc(n)
8 for i in 0..n {
9 buf[i] = rand.next()
10 }
11 return tos(buf)
12}
13*/
14
15// find_between_pair_byte returns the string found between the pair of marks defined
16// by `start` and `end`.
17// As opposed to the `find_between`, `all_after*`, `all_before*` methods defined on the
18// `string` type, this function can extract content between *nested* marks in `input`.
19// If `start` and `end` marks are nested in `input`, the characters
20// between the *outermost* mark pair is returned. It is expected that `start` and `end`
21// marks are *balanced*, meaning that the amount of `start` marks equal the
22// amount of `end` marks in the `input`. An empty string is returned otherwise.
23// Using two identical marks as `start` and `end` results in undefined output behavior.
24// find_between_pair_byte is the fastest in the find_between_pair_* family of functions.
25// Example: assert strings.find_between_pair_u8('(V) (NOT V)',`(`,`)`) == 'V'
26// Example: assert strings.find_between_pair_u8('s {X{Y}} s',`{`,`}`) == 'X{Y}'
27pub fn find_between_pair_u8(input string, start u8, end u8) string {
28 mut marks := 0
29 mut start_index := -1
30 for i, b in input {
31 if b == start {
32 if start_index == -1 {
33 start_index = i + 1
34 }
35 marks++
36 continue
37 }
38 if start_index > 0 {
39 if b == end {
40 marks--
41 if marks == 0 {
42 return input[start_index..i]
43 }
44 }
45 }
46 }
47 return ''
48}
49
50// find_between_pair_rune returns the string found between the pair of marks defined by `start` and `end`.
51// As opposed to the `find_between`, `all_after*`, `all_before*` methods defined on the
52// `string` type, this function can extract content between *nested* marks in `input`.
53// If `start` and `end` marks are nested in `input`, the characters
54// between the *outermost* mark pair is returned. It is expected that `start` and `end`
55// marks are *balanced*, meaning that the amount of `start` marks equal the
56// amount of `end` marks in the `input`. An empty string is returned otherwise.
57// Using two identical marks as `start` and `end` results in undefined output behavior.
58// find_between_pair_rune is inbetween the fastest and slowest in the find_between_pair_* family of functions.
59// Example: assert strings.find_between_pair_rune('(V) (NOT V)',`(`,`)`) == 'V'
60// Example: assert strings.find_between_pair_rune('s {X{Y}} s',`{`,`}`) == 'X{Y}'
61pub fn find_between_pair_rune(input string, start rune, end rune) string {
62 mut marks := 0
63 mut start_index := -1
64 runes := input.runes()
65 for i, r in runes {
66 if r == start {
67 if start_index == -1 {
68 start_index = i + 1
69 }
70 marks++
71 continue
72 }
73 if start_index > 0 {
74 if r == end {
75 marks--
76 if marks == 0 {
77 return runes[start_index..i].string()
78 }
79 }
80 }
81 }
82 return ''
83}
84
85// find_between_pair_string returns the string found between the pair of marks defined by `start` and `end`.
86// As opposed to the `find_between`, `all_after*`, `all_before*` methods defined on the
87// `string` type, this function can extract content between *nested* marks in `input`.
88// If `start` and `end` marks are nested in `input`, the characters
89// between the *outermost* mark pair is returned. It is expected that `start` and `end`
90// marks are *balanced*, meaning that the amount of `start` marks equal the
91// amount of `end` marks in the `input`. An empty string is returned otherwise.
92// Using two identical marks as `start` and `end` results in undefined output behavior.
93// find_between_pair_string is the slowest in the find_between_pair_* function family.
94// Example: assert strings.find_between_pair_string('/*V*/ /*NOT V*/','/*','*/') == 'V'
95// Example: assert strings.find_between_pair_string('s {{X{{Y}}}} s','{{','}}') == 'X{{Y}}'
96pub fn find_between_pair_string(input string, start string, end string) string {
97 mut start_index := -1
98 mut marks := 0
99 start_runes := start.runes()
100 end_runes := end.runes()
101 runes := input.runes()
102 mut i := 0
103 for ; i < runes.len; i++ {
104 start_slice := runes#[i..i + start_runes.len]
105 if start_slice == start_runes {
106 i = i + start_runes.len - 1
107 if start_index < 0 {
108 start_index = i + 1
109 }
110 marks++
111 continue
112 }
113 if start_index > 0 {
114 end_slice := runes#[i..i + end_runes.len]
115 if end_slice == end_runes {
116 marks--
117 if marks == 0 {
118 return runes[start_index..i].string()
119 }
120 i = i + end_runes.len - 1
121 continue
122 }
123 }
124 }
125 return ''
126}
127
128// split_capital returns an array containing the contents of `s` split by capital letters.
129// Example: assert strings.split_capital('XYZ') == ['X', 'Y', 'Z']
130// Example: assert strings.split_capital('XYStar') == ['X', 'Y', 'Star']
131pub fn split_capital(s string) []string {
132 mut res := []string{}
133 mut word_start := 0
134 for idx, c in s {
135 if c.is_capital() {
136 if word_start != idx {
137 res << s#[word_start..idx]
138 }
139 word_start = idx
140 continue
141 }
142 }
143 if word_start != s.len {
144 res << s#[word_start..]
145 }
146 return res
147}
148