## string-substitution.pkg -- a string substitution facility.
## (C) 2001 Lucent Technologies, Bell Labs
## author: Matthias Blume (blume@research.bell-labs.com)
# Compiled by:
#
src/app/makelib/stuff/makelib-stuff.sublibpackage string_substitution
:
api {
Substitution = substring::Substring -> Null_Or( String );
# Given the spec (1st argument), scan the second argument for
# all occurences of prefixes and try the substitutions (left-to-right)
# associated with the matching prefix until one matches.
substitute: List {
prefix: String,
substitutions: List( Substitution )
}
-> String
-> String;
# A simple string replacement substitution
subfor: String -> String -> Substitution;
# Given prefix length and stop character,
# use a given substitution on the subslice
# without prefix and stop char
submap: (Int
, Char)
-> Substitution
-> Substitution;
# A list selection substitution:
# The first argument is the general spec, the second argument is the
# list to select from. The general spec consists of:
# - the length of the prefix (the prefix will be ignored),
# - the stop character (which will also be ignored
# - a selector that extracts the substitution string from a list element
# - a separator string used when n = 0 or missing (the whole list gets
# inserted in this case, with the separator string separating elements)
subnsel: (Int
, Char
, (X -> String)
, String)
-> List(X)
-> Substitution;
}
{
package ss= substring; # substring is from
src/lib/std/substring.pkg Substitution = ss::Substring -> Null_Or( String );
fun substitute rules
=
do_it
where
rules
=
map (\\ { prefix, substitutions }
=
{ prefix => ss::from_string prefix, substitutions })
rules;
fun do_it s
=
loop (0, 0, [])
where
len = size s;
fun loop (i0, i, acc)
=
{ fun matchingrule { prefix, substitutions }
=
{ plen = ss::size prefix;
i + plen <= len
and
ss::compare (prefix, ss::make_substring (s, i, plen)) == EQUAL;
};
fun findrule ()
=
null_or::map .substitutions (list::find matchingrule rules);
fun newacc k
=
if (k > i0)
ss::make_substring (s, i0, k - i0) ! acc;
else
acc;
fi;
if (i >= len)
ss::cat (reverse (newacc len));
else
case (findrule ())
NULL => loop (i0, i + 1, acc);
THE substitutions
=>
{ acc = newacc i;
fun dosubst j
=
{ fun finddosubst []
=>
dosubst (j + 1);
finddosubst (replace ! sl)
=>
{ ss = ss::make_substring (s, i, j - i);
case (replace ss)
NULL => finddosubst sl;
THE r
=>
loop (j, j, ss::from_string r ! acc);
esac;
};
end;
if (j > len)
loop (i, len, acc);
else
finddosubst substitutions;
fi;
};
dosubst (i + 1);
};
esac;
fi;
};
end;
end;
fun subfor p r ss
=
if (substring::compare (substring::from_string p, ss) == EQUAL)
THE r;
else NULL; fi;
fun submap (plen, stopchar) m ss
=
{ sslen = ss::size ss;
if (ss::get (ss, sslen - 1) == stopchar)
m (ss::make_slice (ss, plen, THE (sslen - plen - 1)));
else
NULL;
fi;
};
fun subnsel (plen, stopchar, sel, sep) l ss
=
submap (plen, stopchar) m ss
where
fun m numslice
=
{ nums = ss::to_string numslice;
fun all ()
=
THE (string::join sep (map sel l));
fun seli i
=
THE ( sel (list::nth (l, i))
except
exceptions::INDEX_OUT_OF_BOUNDS = ss::to_string ss
);
if (nums == "")
all ();
else
case (int::from_string nums)
THE 0 => all ();
THE i => seli (i - 1);
NULL => THE (ss::to_string ss);
esac;
fi;
};
end;
};