I’ve been doing the Weekly
Challenges. The
latest
involved mucking about with strings. (Note that this ends today.)
Task 1: Find Words
You are given a list of words and a character.
Write a script to return the index of word in the list where you
find the given character.
So basically this is a straightforward mapping. In Perl:
sub findwords($a, $b) {
my @out;
while (my ($i, $x) = each @{$a}) {
if (index($x, $b) > -1) {
push @out, $i;
}
}
\@out;
}
Functionally, in Postscript:
/findwords {
0 dict begin
/b exch def
[ exch
enumerate.array {
aload pop
/x exch def
/i exch def
x b search {
pop
pop
pop
i
} {
pop
} ifelse
} forall
]
end
} bind def
Task 2: Find Third
You are given a sentence and two words.
Write a script to return all words in the given sentence that appear
in sequence to the given two words.
Splitting the string is the more interesting part of the problem,
given that there can be punctuation. With regexps I'd just global
match ([A-Za-z]+)
but I didn't want the weight of that in my
solutions in other languages, so I wrote a character by character
parser instead.
fn findthird(s: &str, a: &str, b: &str) -> Vec<String> {
ss
is the list of strings, sa
is the current working string.
let mut ss: Vec<String> = Vec::new();
let mut sa = String::new();
for c in s.chars() {
match c {
If the character is a letter, append it to the current working string.
'A'..='Z' | 'a'..='z' => {
sa.push(c);
}
Otherwise, stick the working string (if any) on the list and clear it.
_ => {
if sa.len() > 0 {
ss.push(sa.clone());
sa = String::new();
}
}
};
}
If there was any working string left at the end (i.e. we ended with a
letter), stick that last string on too.
if sa.len() > 0 {
ss.push(sa);
}
Now just check each string triplet (in order) and record the third
string where the first two match.
let mut out: Vec<String> = Vec::new();
for p in ss.windows(3) {
if p[0] == a && p[1] == b {
out.push(p[2].clone());
}
}
out
}
Full code on
github.