1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

builtin: add string.replace_char and string.normalize_tabs (#15239)

This commit is contained in:
l-m 2022-07-28 05:04:39 +10:00 committed by GitHub
parent 60094d95e2
commit 10f3c9f127
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 81 additions and 0 deletions

View File

@ -495,6 +495,75 @@ pub fn (s string) replace_each(vals []string) string {
}
}
// replace_char replaces all occurences of the character `rep` multiple occurences of the character passed in `with` with respect to `repeat`.
// Example: assert '\tHello!'.replace_char(`\t`,` `,8) == ' Hello!'
[direct_array_access]
pub fn (s string) replace_char(rep u8, with u8, repeat int) string {
$if !no_bounds_checking ? {
if repeat <= 0 {
panic('string.replace_char(): tab length too short')
}
}
if s.len == 0 {
return s.clone()
}
// TODO Allocating ints is expensive. Should be a stack array
// - string.replace()
mut idxs := []int{cap: s.len}
defer {
unsafe { idxs.free() }
}
// No need to do a contains(), it already traverses the entire string
for i, ch in s {
if ch == rep { // Found char? Mark its location
idxs << i
}
}
if idxs.len == 0 {
return s.clone()
}
// Now we know the number of replacements we need to do and we can calc the len of the new string
new_len := s.len + idxs.len * (repeat - 1)
mut b := unsafe { malloc_noscan(new_len + 1) } // add space for the null byte at the end
// Fill the new string
mut b_i := 0
mut s_idx := 0
for rep_pos in idxs {
for i in s_idx .. rep_pos { // copy everything up to piece being replaced
unsafe {
b[b_i] = s[i]
}
b_i++
}
s_idx = rep_pos + 1 // move string index past replacement
for _ in 0 .. repeat { // copy replacement piece
unsafe {
b[b_i] = with
}
b_i++
}
}
if s_idx < s.len { // if any original after last replacement, copy it
for i in s_idx .. s.len {
unsafe {
b[b_i] = s[i]
}
b_i++
}
}
unsafe {
b[new_len] = 0
return tos(b, new_len)
}
}
// normalize_tabs replaces all tab characters with `tab_len` amount of spaces
// Example: assert '\t\tpop rax\t; pop rax'.normalize_tabs(2) == ' pop rax ; pop rax'
[inline]
pub fn (s string) normalize_tabs(tab_len int) string {
return s.replace_char(`\t`, ` `, tab_len)
}
// bool returns `true` if the string equals the word "true" it will return `false` otherwise.
pub fn (s string) bool() bool {
return s == 'true' || s == 't' // TODO t for pg, remove

View File

@ -380,6 +380,18 @@ fn test_replace_each() {
assert s2.replace_each(['hello_world', 'aaa', 'hello', 'bbb']) == 'aaa bbb'
}
fn test_replace_char() {
assert 'azert'.replace_char(`z`, `s`, 2) == 'assert'
assert '\rHello!\r'.replace_char(`\r`, `\n`, 1) == '\nHello!\n'
assert 'Hello!'.replace_char(`l`, `e`, 4) == 'Heeeeeeeeeo!'
assert '1141'.replace_char(`1`, `8`, 2) == '8888488'
}
fn test_normalize_tabs() {
assert '\t\tHello!'.normalize_tabs(4) == ' Hello!'
assert '\t\tHello!\t; greeting'.normalize_tabs(1) == ' Hello! ; greeting'
}
fn test_itoa() {
num := 777
assert num.str() == '777'