Skip to content

Commit 39295b7

Browse files
committed
Added function for finding the first substring/character in a string.
1 parent 02a7897 commit 39295b7

3 files changed

Lines changed: 142 additions & 4 deletions

File tree

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def find_all_files(directory, endings=None):
3030

3131
setup(
3232
name='vunit_hdl',
33-
version='0.47.0',
33+
version='0.48.0',
3434
packages=['vunit',
3535
'vunit.com',
3636
'vunit.test',

vunit/vhdl/string_ops/src/string_ops.vhd

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@ package string_ops is
2727
constant start : natural := 0;
2828
constant stop : natural := 0)
2929
return natural;
30+
function find (
31+
constant s : string;
32+
constant substring : string;
33+
constant start : natural := 0;
34+
constant stop : natural := 0)
35+
return natural;
36+
function find (
37+
constant s : string;
38+
constant char : character;
39+
constant start : natural := 0;
40+
constant stop : natural := 0)
41+
return natural;
3042
function strip (
3143
str : string;
3244
chars : string := " ")
@@ -116,16 +128,48 @@ package body string_ops is
116128
end if;
117129
end function offset;
118130

119-
function in_range (
131+
function index (
132+
constant s : string;
133+
constant offset : natural)
134+
return positive is
135+
begin
136+
if s'ascending then
137+
return s'left + offset;
138+
else
139+
return s'left - offset;
140+
end if;
141+
end function index;
142+
143+
function left_of_range (
120144
constant s : string;
121145
constant index : natural)
122146
return boolean is
123147
begin
124148
if s'ascending then
125-
return (index >= s'left) and (index <= s'right);
149+
return (index < s'left);
126150
else
127-
return (index <= s'left) and (index >= s'right);
151+
return (index > s'left);
128152
end if;
153+
end function left_of_range;
154+
155+
function right_of_range (
156+
constant s : string;
157+
constant index : natural)
158+
return boolean is
159+
begin
160+
if s'ascending then
161+
return (index > s'right);
162+
else
163+
return (index < s'right);
164+
end if;
165+
end function right_of_range;
166+
167+
function in_range (
168+
constant s : string;
169+
constant index : natural)
170+
return boolean is
171+
begin
172+
return not left_of_range(s, index) and not right_of_range(s, index);
129173
end function in_range;
130174

131175
function slice (
@@ -448,6 +492,60 @@ package body string_ops is
448492
return n;
449493
end count;
450494

495+
function find (
496+
constant s : string;
497+
constant char : character;
498+
constant start : natural := 0;
499+
constant stop : natural := 0)
500+
return natural is
501+
variable substring : string(1 to 1);
502+
begin
503+
substring(1) := char;
504+
return find(s, substring, start, stop);
505+
end;
506+
507+
function find (
508+
constant s : string;
509+
constant substring : string;
510+
constant start : natural := 0;
511+
constant stop : natural := 0)
512+
return natural is
513+
variable start_pos, stop_pos : natural;
514+
variable o : natural;
515+
begin
516+
if start = 0 or left_of_range(s, start) then
517+
start_pos := s'left;
518+
elsif right_of_range(s, start) then
519+
return 0;
520+
else
521+
start_pos := start;
522+
end if;
523+
524+
if stop = 0 or right_of_range(s, stop) then
525+
stop_pos := s'right;
526+
elsif left_of_range(s, stop) then
527+
return 0;
528+
else
529+
stop_pos := stop;
530+
end if;
531+
532+
if substring = "" then
533+
return start_pos;
534+
end if;
535+
536+
o := offset(s, start_pos);
537+
while o <= offset(s, stop_pos) - substring'length + 1 loop
538+
if slice(s, o, substring'length) = substring then
539+
return index(s, o);
540+
end if;
541+
542+
o := o + 1;
543+
end loop;
544+
545+
return 0;
546+
547+
end find;
548+
451549
impure function split (
452550
constant s : string;
453551
constant sep : string;

vunit/vhdl/string_ops/test/tb_string_ops.vhd

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,46 @@ begin
130130
counting_assert(count(reverse_string, "a", 12 ,4) = 0, "Should not find anything outside of the string");
131131
counting_assert(count("aba", "a", 3 ,1) = 0, "Should not find anything within a negative range");
132132
counting_assert(count("aba", "abab") = 0, "Should not find anything when substring is longer than the string");
133+
elsif run("Test find") then
134+
counting_assert(find("", "") = 1, "Empty string should be found at the start");
135+
counting_assert(find("foo bar", "") = 1, "Empty string should be found at the start");
136+
counting_assert(find("foo bar", "foo") = 1, "Should find string at the start");
137+
counting_assert(find("foo bar", "bar") = 5, "Should find string at the end");
138+
counting_assert(find("foo bar", "o b") = 3, "Should find string in the middle");
139+
counting_assert(find("foo bar", "foo bar") = 1, "Should find full string");
140+
counting_assert(find("foo bar", 'f') = 1, "Should find character at the start");
141+
counting_assert(find("foo bar", 'r') = 7, "Should find character at the end");
142+
counting_assert(find("foo bar", ' ') = 4, "Should find character in the middle");
143+
counting_assert(find("foo bar", "bars") = 0, "Should return 0 when string not found");
144+
counting_assert(find("foo bar", "foo bars") = 0, "Should return 0 when string not found");
145+
counting_assert(find("foo bar", 'q') = 0, "Should return 0 when character not found");
146+
counting_assert(find(offset_string, "") = 10, "Empty string should be found at the start on offset string");
147+
counting_assert(find(offset_string, "foo") = 10, "Should find string at the start on offset string");
148+
counting_assert(find(offset_string, "bar") = 14, "Should find string at the end on offset string");
149+
counting_assert(find(offset_string, "o b") = 12, "Should find string in the middle on offset string");
150+
counting_assert(find(reverse_string, "") = 16, "Empty string should be found at the start on reversed string");
151+
counting_assert(find(reverse_string, "foo") = 16, "Should find string at the start on reversed string");
152+
counting_assert(find(reverse_string, "bar") = 12, "Should find string at the end on reversed string");
153+
counting_assert(find(reverse_string, "o b") = 14, "Should find string in the middle on reversed string");
154+
counting_assert(find("foo bar", "oo", 2, 6) = 2, "Should find string at the start of slice");
155+
counting_assert(find("foo bar", "ba", 2, 6) = 5, "Should find string at the end of slice");
156+
counting_assert(find("foo bar", "o b", 2, 6) = 3, "Should find string in the middle of slice");
157+
counting_assert(find("foo bar", "", 2, 6) = 2, "Empty string should be found at the start of slice");
158+
counting_assert(find("foo bar", 'f', 2, 6) = 0, "Should not find anything before slice");
159+
counting_assert(find("foo bar", "ar", 2, 6) = 0, "Should not find anything after slice");
160+
counting_assert(find(offset_string, 'f', 11, 15) = 0, "Should not find anything before slice in offset string");
161+
counting_assert(find(offset_string, "ar", 11, 15) = 0, "Should not find anything after slice in offset string");
162+
counting_assert(find(reverse_string, 'f', 15, 11) = 0, "Should not find anything before slice in reversed string");
163+
counting_assert(find(reverse_string, "ar", 15, 11) = 0, "Should not find anything after slice in reversed string");
164+
counting_assert(find("foo bar", "o b", 1, 100) = 3, "Should find in ranges wider than input'range");
165+
counting_assert(find("foo bar", "zen", 1, 100) = 0, "Should not find in ranges wider than input'range");
166+
counting_assert(find(offset_string, "o b", 1, 100) = 12, "Should find in ranges wider than input'range");
167+
counting_assert(find(offset_string, "zen", 1, 100) = 0, "Should not find in ranges wider than input'range");
168+
counting_assert(find(reverse_string, "o b", 100, 1) = 14, "Should find in ranges wider than input'range");
169+
counting_assert(find(reverse_string, "zen", 100, 1) = 0, "Should not find in ranges wider than input'range");
170+
counting_assert(find("foo bar", "o b", 3, 2) = 0, "Should not find string in negative range");
171+
counting_assert(find("foo bar", "o b", 30, 0) = 0, "Should not find string in negative range");
172+
counting_assert(find(reverse_string, "o b", 1, 100) = 0, "Should not find string in negative range");
133173

134174
elsif run("Test image") then
135175
counting_assert(image("") = "", "Should return empty string on empty input vector.");

0 commit comments

Comments
 (0)