mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 23:28:48 +00:00
strings: add substring, substring_to and substring_from
This commit is contained in:
@@ -3316,3 +3316,106 @@ levenshtein_distance :: proc(a, b: string, allocator := context.allocator, loc :
|
|||||||
|
|
||||||
return costs[n], nil
|
return costs[n], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
internal_substring :: proc(s: string, rune_start: int, rune_end: int) -> (sub: string, ok: bool) {
|
||||||
|
sub = s
|
||||||
|
ok = true
|
||||||
|
|
||||||
|
rune_i: int
|
||||||
|
|
||||||
|
if rune_start > 0 {
|
||||||
|
ok = false
|
||||||
|
for _, i in sub {
|
||||||
|
if rune_start == rune_i {
|
||||||
|
ok = true
|
||||||
|
sub = sub[i:]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
rune_i += 1
|
||||||
|
}
|
||||||
|
if !ok { return }
|
||||||
|
}
|
||||||
|
|
||||||
|
if rune_end >= rune_start {
|
||||||
|
ok = false
|
||||||
|
for _, i in sub {
|
||||||
|
if rune_end == rune_i {
|
||||||
|
ok = true
|
||||||
|
sub = sub[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
rune_i += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if rune_end == rune_i {
|
||||||
|
ok = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns a substring of `s` that starts at rune index `rune_start` and goes up to `rune_end`.
|
||||||
|
|
||||||
|
Think of it as slicing `s[rune_start:rune_end]` but rune-wise.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- s: the string to substring
|
||||||
|
- rune_start: the start (inclusive) rune
|
||||||
|
- rune_end: the end (exclusive) rune
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- sub: the substring
|
||||||
|
- ok: whether the rune indexes where in bounds of the original string
|
||||||
|
*/
|
||||||
|
substring :: proc(s: string, rune_start: int, rune_end: int) -> (sub: string, ok: bool) {
|
||||||
|
if rune_start < 0 || rune_end < 0 || rune_end < rune_start {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return internal_substring(s, rune_start, rune_end)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns a substring of `s` that starts at rune index `rune_start` and goes up to the end of the string.
|
||||||
|
|
||||||
|
Think of it as slicing `s[rune_start:]` but rune-wise.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- s: the string to substring
|
||||||
|
- rune_start: the start (inclusive) rune
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- sub: the substring
|
||||||
|
- ok: whether the rune indexes where in bounds of the original string
|
||||||
|
*/
|
||||||
|
substring_from :: proc(s: string, rune_start: int) -> (sub: string, ok: bool) {
|
||||||
|
if rune_start < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return internal_substring(s, rune_start, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns a substring of `s` that goes up to rune index `rune_end`.
|
||||||
|
|
||||||
|
Think of it as slicing `s[:rune_end]` but rune-wise.
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- s: the string to substring
|
||||||
|
- rune_end: the end (exclusive) rune
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- sub: the substring
|
||||||
|
- ok: whether the rune indexes where in bounds of the original string
|
||||||
|
*/
|
||||||
|
substring_to :: proc(s: string, rune_end: int) -> (sub: string, ok: bool) {
|
||||||
|
if rune_end < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return internal_substring(s, -1, rune_end)
|
||||||
|
}
|
||||||
|
|||||||
@@ -124,3 +124,34 @@ test_case_conversion :: proc(t: ^testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_substring :: proc(t: ^testing.T) {
|
||||||
|
Case :: struct {
|
||||||
|
s: string,
|
||||||
|
start: int,
|
||||||
|
end: int,
|
||||||
|
sub: string,
|
||||||
|
ok: bool,
|
||||||
|
}
|
||||||
|
cases := []Case {
|
||||||
|
{ok = true},
|
||||||
|
{s = "", start = -1, ok = false},
|
||||||
|
{s = "", end = -1, ok = false},
|
||||||
|
{s = "", end = +1, ok = false},
|
||||||
|
{s = "Hello", end = len("Hello"), sub = "Hello", ok = true},
|
||||||
|
{s = "Hello", start = 1, end = len("Hello"), sub = "ello", ok = true},
|
||||||
|
{s = "Hello", start = 1, end = len("Hello") - 1, sub = "ell", ok = true},
|
||||||
|
{s = "Hello", end = len("Hello") + 1, sub = "Hello", ok = false},
|
||||||
|
{s = "小猫咪", start = 0, end = 3, sub = "小猫咪", ok = true},
|
||||||
|
{s = "小猫咪", start = 1, end = 3, sub = "猫咪", ok = true},
|
||||||
|
{s = "小猫咪", start = 1, end = 5, sub = "猫咪", ok = false},
|
||||||
|
{s = "小猫咪", start = 1, end = 1, sub = "", ok = true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tc in cases {
|
||||||
|
sub, ok := strings.substring(tc.s, tc.start, tc.end)
|
||||||
|
testing.expectf(t, ok == tc.ok, "expected %v[%v:%v] to return ok: %v", tc.s, tc.start, tc.end, tc.ok)
|
||||||
|
testing.expectf(t, sub == tc.sub, "expected %v[%v:%v] to return sub: %v, got: %v", tc.s, tc.start, tc.end, tc.sub, sub)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user