1 String handling
share/lib/std/strings/__init__.flx
include "std/strings/string"; include "std/strings/cstring"; include "std/strings/ustr"; include "std/strings/ucstr";
2 Strings
We have three string like things. cstring
is just
an alias for a NTBS (Null Terminated Byte String).
The workhorse string
type based on C++ string.
A ustring
is a unicode representation using a 32 bit unsigned integer as
the character base.
This type is deprecated, to be repalced by C++11 unicode string type.
share/lib/std/strings/string.flx
typedef cstring = +char; type string = "::std::basic_string<char>" requires index TYPE_string, Cxx_headers::string, header ' ', encoder "::flx::gc::generic::string_encoder", decoder "::flx::gc::generic::string_decoder" ; typeset strings = {string}; class Str [T] { virtual fun str: T -> string; } class Repr [T with Str[T]] { virtual fun repr (t:T) : string => str t; } class Show [T] { inherit Str[T]; inherit Repr[T]; }
2.1 Equality and total ordering
share/lib/std/strings/string.flx
instance[t in strings] Eq[t] { fun == : t * t -> bool = "$1==$2"; } instance[t in strings] Tord[t] { fun < : t * t -> bool = "$1<$2"; } class String { inherit Eq[string]; inherit Tord[string];
2.2 Equality of string
and char
share/lib/std/strings/string.flx
fun == (s:string, c:char) => len s == 1uz and s.[0] == c; fun == (c:char, s:string) => len s == 1uz and s.[0] == c; fun != (s:string, c:char) => len s != 1uz or s.[0] != c; fun != (c:char, s:string) => len s != 1uz or s.[0] != c;
2.3 Append to string
object
share/lib/std/strings/string.flx
proc += : &string * string = "$1->append($2:assign);"; proc += : &string * +char = "$1->append($2:assign);"; proc += : &string * char = "*$1 += $2;"; proc += : &string * &string = "$1->append(*$2);";
2.4 Length of string
share/lib/std/strings/string.flx
// we need to cast to an int so that c++ won't complain fun len: string -> size = "$1.size()"; fun len: &string -> size = "$1->size()";
2.5 String concatenation.
share/lib/std/strings/string.flx
fun + : string * string -> string = "$1+$2"; fun + : string * carray[char] -> string = "$1+$2"; fun + : string * char -> string = "$1+$2"; fun + : char * string -> string = "$1+$2"; //fun + : string * int -> string = "$1+::flx::rtl::i18n::utf8($2:assign)" is add requires package "flx_i18n"; fun + ( x:string, y: int) => x + str y; // may be a bit risky! // IT WAS: interferes with "hello" + list ("world","blah"): // is this a string or a list of strings? //fun + [T with Str[T]] (x:string, y:T) => x + str y;
2.6 Repetition of string
or char
share/lib/std/strings/string.flx
fun * : string * int -> string = "::flx::rtl::strutil::mul($1:assign,$2:assign)" requires package "flx_strutil"; fun * : char * int -> string = "::std::string($2:assign,$1:assign)";
2.7 Application of string
to string
or int
is concatenation
share/lib/std/strings/string.flx
fun apply (x:string, y:string):string => x + y; fun apply (x:string, y:int):string => x + y;
2.8 Construct a char from first byte of a string
.
Returns nul char (code 0) if the string is empty.
share/lib/std/strings/string.flx
ctor char (x:string) => x.[0];
2.9 Constructors for string
share/lib/std/strings/string.flx
ctor string (c:char) => ""+c; ctor string: +char = "::std::string($1:assign)"; ctor string: +char * !ints = "::std::string($1:assign,$2:assign)"; fun utf8: int -> string = "::flx::rtl::i18n::utf8($1)" requires package "flx_i18n";
2.10 Substrings
share/lib/std/strings/string.flx
fun subscript: string * !ints -> char = "::flx::rtl::strutil::subscript($1:assign,$2:assign)" requires package "flx_strutil"; fun copyfrom: string * !ints -> string = "::flx::rtl::strutil::substr($1:assign,$2:assign,$1:postfix.size())" requires package "flx_strutil"; fun copyto: string * !ints -> string = "::flx::rtl::strutil::substr($1:assign,0,$2:assign)" requires package "flx_strutil"; fun substring: string * !ints * !ints -> string = "::flx::rtl::strutil::substr($1:assign,$2:assign,$3:assign)" requires package "flx_strutil"; fun subscript (x:string, s:slice[int]):string => match s with | #Slice_all => substring (x, 0, x.len.int) | Slice_from (start) => copyfrom (x, start) | Slice_to_incl (end) => copyto (x, end + 1) | Slice_to_excl (end) => copyto (x, end) | Slice_range_incl (start, end) => substring (x, start, end + 1) | Slice_range_excl (start, end) => substring (x, start, end) | Slice_from_counted (start, count) => substring (x,start, start + count) | Slice_one (index) => string x.[index] endmatch ; fun apply (s:slice[int], x:string) => subscript (x,s); fun apply (i:int, x:string) => subscript (x,i); fun subscript (x:string, gs:gslice[int]):string = { var r = ""; match gs with | GSlice s => r = subscript(x,s); | GSSList gsl => // this should be faster cause it cats a list of string which // is linear in the number of strings var sl = Empty[string]; for gs in gsl perform sl = subscript (x,gs) + sl; r = sl.rev.(cat ""); | _ => for i in gs perform r += x.[i]; endmatch; return r; } proc store: &string * !ints * char = "(*$1)[$2] = $3;";
2.11 Map a string char
by char
share/lib/std/strings/string.flx
fun map (f:char->char) (var x:string): string = { if len x > 0uz do for var i in 0uz upto (len x) - 1uz do store(&x, i, f x.[i]); done done return x; }
2.12 STL string functions
These come in two flavours: the standard C++ operations
which return stl_npos
on failure, and a more Felix
like variant which uses an option
type.
share/lib/std/strings/string.flx
const stl_npos: size = "::std::string::npos"; fun stl_find: string * string -> size = "$1.find($2)" is cast; fun stl_find: string * string * size -> size = "$1.find($2,$3)" is cast; fun stl_find: string * +char -> size = "$1.find($2)" is cast; fun stl_find: string * +char * size -> size = "$1.find($2,$3)" is cast; fun stl_find: string * char -> size = "$1.find($2)" is cast; fun stl_find: string * char * size -> size = "$1.find($2,$3)" is cast; fun find (s:string, e:string) : opt[size] => match stl_find (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find (s:string, e:string, i:size) : opt[size] => match stl_find (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find (s:string, e:+char) : opt[size] => match stl_find (s, e) with | i when i== stl_npos => None[size] | i => Some i endmatch; fun find (s:string, e:+char, i:size) : opt[size] => match stl_find (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find (s:string, e:char) : opt[size] => match stl_find (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find (s:string, e:char, i:size) : opt[size] => match stl_find (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun stl_rfind: string * string -> size = "$1.rfind($2)"; fun stl_rfind: string * string * size -> size = "$1.rfind($2,$3)"; fun stl_rfind: string * +char-> size = "$1.rfind($2)"; fun stl_rfind: string * +char * size -> size = "$1.rfind($2,$3)"; fun stl_rfind: string * char -> size = "$1.rfind($2)"; fun stl_rfind: string * char * size -> size = "$1.rfind($2,$3)"; fun rfind (s:string, e:string) : opt[size] => match stl_rfind (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun rfind (s:string, e:string, i:size) : opt[size] => match stl_rfind (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun rfind (s:string, e:+char) : opt[size] => match stl_rfind (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun rfind (s:string, e:+char, i:size) : opt[size] => match stl_rfind (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun rfind (s:string, e:char) : opt[size] => match stl_rfind (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun rfind (s:string, e:char, i:size) : opt[size] => match stl_rfind (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun stl_find_first_of: string * string -> size = "$1.find_first_of($2)"; fun stl_find_first_of: string * string * size -> size = "$1.find_first_of($2,$3)"; fun stl_find_first_of: string * +char -> size = "$1.find_first_of($2)"; fun stl_find_first_of: string * +char * size -> size = "$1.find_first_of($2,$3)"; fun stl_find_first_of: string * char -> size = "$1.find_first_of($2)"; fun stl_find_first_of: string * char * size -> size = "$1.find_first_of($2,$3)"; fun find_first_of (s:string, e:string) : opt[size] => match stl_find_first_of (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_first_of (s:string, e:string, i:size) : opt[size] => match stl_find_first_of (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_first_of (s:string, e:+char) : opt[size] => match stl_find_first_of (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_first_of (s:string, e:+char, i:size) : opt[size] => match stl_find_first_of (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_first_of (s:string, e:char) : opt[size] => match stl_find_first_of (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_first_of (s:string, e:char, i:size) : opt[size] => match stl_find_first_of (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun stl_find_first_not_of: string * string -> size = "$1.find_first_not_of($2)"; fun stl_find_first_not_of: string * string * size -> size = "$1.find_first_not_of($2,$3)"; fun stl_find_first_not_of: string * +char -> size = "$1.find_first_not_of($2)"; fun stl_find_first_not_of: string * +char * size -> size = "$1.find_first_not_of($2,$3)"; fun stl_find_first_not_of: string * char -> size = "$1.find_first_not_of($2)"; fun stl_find_first_not_of: string * char * size -> size = "$1.find_first_not_of($2,$3)"; fun find_first_not_of (s:string, e:string) : opt[size] => match stl_find_first_not_of (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_first_not_of (s:string, e:string, i:size) : opt[size] => match stl_find_first_not_of (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_first_not_of (s:string, e:+char) : opt[size] => match stl_find_first_not_of (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_first_not_of (s:string, e:+char, i:size) : opt[size] => match stl_find_first_not_of (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_first_not_of (s:string, e:char) : opt[size] => match stl_find_first_not_of (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_first_not_of (s:string, e:char, i:size) : opt[size] => match stl_find_first_not_of (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun stl_find_last_of: string * string -> size = "$1.find_last_of($2)"; fun stl_find_last_of: string * string * size -> size = "$1.find_last_of($2,$3)"; fun stl_find_last_of: string * +char -> size = "$1.find_last_of($2)"; fun stl_find_last_of: string * +char * size -> size = "$1.find_last_of($2,$3)"; fun stl_find_last_of: string * char -> size = "$1.find_last_of($2)"; fun stl_find_last_of: string * char * size -> size = "$1.find_last_of($2,$3)"; fun find_last_of (s:string, e:string) : opt[size] => match stl_find_last_of (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_last_of (s:string, e:string, i:size) : opt[size] => match stl_find_last_of (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_last_of (s:string, e:+char) : opt[size] => match stl_find_last_of (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_last_of (s:string, e:+char, i:size) : opt[size] => match stl_find_last_of (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_last_of (s:string, e:char) : opt[size] => match stl_find_last_of (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_last_of (s:string, e:char, i:size) : opt[size] => match stl_find_last_of (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun stl_find_last_not_of: string * string -> size = "$1.find_last_not_of($2)"; fun stl_find_last_not_of: string * string * size -> size = "$1.find_last_not_of($2,$3)"; fun stl_find_last_not_of: string * +char -> size = "$1.find_last_not_of($2)"; fun stl_find_last_not_of: string * +char * size -> size = "$1.find_last_not_of($2,$3)"; fun stl_find_last_not_of: string * char -> size = "$1.find_last_not_of($2)"; fun stl_find_last_not_of: string * char * size -> size = "$1.find_last_not_of($2,$3)"; fun find_last_not_of (s:string, e:string) : opt[size] => match stl_find_last_not_of (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_last_not_of (s:string, e:string, i:size) : opt[size] => match stl_find_last_not_of (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_last_not_of (s:string, e:+char) : opt[size] => match stl_find_last_not_of (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_last_not_of (s:string, e:+char, i:size) : opt[size] => match stl_find_last_not_of (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_last_not_of (s:string, e:char) : opt[size] => match stl_find_last_not_of (s, e) with | i when i == stl_npos => None[size] | i => Some i endmatch; fun find_last_not_of (s:string, e:char, i:size) : opt[size] => match stl_find_last_not_of (s, e, i) with | i when i == stl_npos => None[size] | i => Some i endmatch;
2.13 Construe string
as set of char
share/lib/std/strings/string.flx
instance Set[string,char] { fun \(\in\) (c:char, s:string) => stl_find (s,c) != stl_npos; }
2.14 Construe string
as stream of char
share/lib/std/strings/string.flx
instance Iterable[string, char] { gen iterator(var x:string) () = { for var i in 0 upto x.len.int - 1 do yield Some (x.[i]); done return None[char]; } } inherit Streamable[string,char];
2.15 Test if a string has given prefix or suffix
share/lib/std/strings/string.flx
fun prefix(arg:string,key:string)=> arg.[to len key]==key ; fun suffix (arg:string,key:string)=> arg.[-key.len to]==key ; fun startswith (x:string) (e:string) : bool => prefix (x,e); // as above: slices are faster fun endswith (x:string) (e:string) : bool => suffix (x,e); fun startswith (x:string) (e:char) : bool => x.[0] == e; fun endswith (x:string) (e:char) : bool => x.[-1] == e;
2.16 Trim off specified prefix or suffix or both
share/lib/std/strings/string.flx
fun ltrim (x:string) (e:string) : string => if startswith x e then x.[e.len.int to] else x endif ; fun rtrim (x:string) (e:string) : string => if endswith x e then x.[to x.len.int - e.len.int] else x endif ; fun trim (x:string) (e:string) : string => ltrim (rtrim x e) e;
2.17 Strip characters from left, right, or both end of a string.
share/lib/std/strings/string.flx
fun lstrip (x:string, e:string) : string = { if len x > 0uz do for var i in 0uz upto len x - 1uz do var found = false; for var j in 0uz upto len e - 1uz do if x.[i] == e.[j] do found = true; done done if not found do return x.[i to]; done done; done return ''; } fun rstrip (x:string, e:string) : string = { if len x > 0uz do for var i in len x - 1uz downto 0uz do var found = false; for var j in 0uz upto len e - 1uz do if x.[i] == e.[j] do found = true; done done if not found do return x.[to i.int + 1]; done done done return ''; } fun strip (x:string, e:string) : string => lstrip(rstrip(x, e), e); fun lstrip (x:string) : string => lstrip(x, " \t\n\r\f\v"); fun rstrip (x:string) : string => rstrip(x, " \t\n\r\f\v"); fun strip (x:string) : string => lstrip$ rstrip x;
2.18 Justify string contents
share/lib/std/strings/string.flx
fun ljust(x:string, width:int) : string => if x.len.int >= width then x else x + (' ' * (width - x.len.int)) endif ; fun rjust(x:string, width:int) : string => if x.len.int >= width then x else (' ' * (width - x.len.int)) + x endif ;
2.19 Split a string into a list on given separator
share/lib/std/strings/string.flx
fun split (x:string, d:char): List::list[string] => unbox (List::rev (rev_split (x,d))); fun rev_split (x:string, d:char): uniq (List::list[string]) = { fun aux (x:string,y:List::list[string]) => match find (x, d) with | #None => Cons (x, y) | Some n => aux$ x.[n+1uz to], List::Cons (x.[to n],y) endmatch ; return box (aux$ x, List::Empty[string]); } fun split (x:string, d:string): List::list[string] => unbox (List::rev (rev_split (x,d))); fun rev_split (x:string, d:string): uniq List::list[string] = { fun aux (pos:size,y:List::list[string]) => match stl_find_first_of (x, d, pos) with | $(stl_npos) => List::Cons (x.[pos to],y) | n => aux$ (n+1uz), List::Cons (x.[pos to n],y) endmatch ; return box (aux$ 0uz, List::Empty[string]); } fun split (x:string, d:+char): List::list[string] => unbox (List::rev (rev_split (x,d))); fun rev_split (x:string, d:+char): uniq (List::list[string]) = { fun aux (x:string,y:List::list[string]) => match find_first_of (x, d) with | #None => List::Cons (x, y) | Some n => aux$ x.[n+1uz to], List::Cons (x.[to n],y) endmatch ; return box (aux$ x, List::Empty[string]); } fun split_first (x:string, d:string): opt[string*string] => match find_first_of (x, d) with | #None => None[string*string] | Some n => Some (x.[to n],substring(x,n+1uz,(len x))) endmatch ; Split a string on whitespace but respecting double quotes, single quotes, and slosh escapes. // leading and trailing space is removed. Embedded // multiple spaces cause a single split. class RespectfulParser { variant quote_action_t = | ignore-quote | keep-quote | drop-quote ; variant dquote_action_t = | ignore-dquote | keep-dquote | drop-dquote ; variant escape_action_t = | ignore-escape | keep-escape | drop-escape ; typedef action_t = (quote:quote_action_t, dquote:dquote_action_t, escape:escape_action_t); variant mode_t = | copying | skipping | quote | dquote | escape-copying | escape-quote | escape-dquote; typedef state_t = (mode:mode_t, current:string, parsed: list[string] ); noinline fun respectful_parse (action:action_t) (var state:state_t) (var s:string) : state_t = { var mode = state.mode; var current = state.current; var result = Empty[string]; noinline proc handlecopying(ch:char) { if ch == char "'" do match action.quote with | #ignore-quote => current += ch; | #keep-quote => current += ch; mode = quote; | #drop-quote => mode = quote; endmatch; elif ch == char '"' do match action.dquote with | #ignore-dquote => current += ch; | #keep-dquote => current += ch; mode = dquote; | #drop-dquote => mode = dquote; endmatch; elif ch == char '\\' do match action.escape with | #ignore-escape => current += ch; | #keep-escape => current += ch; mode = escape-copying; | #drop-escape => mode = escape-copying; endmatch; elif ord ch <= ' '.char.ord do // can't happen if called from skipping result += current; current = ""; mode = skipping; else current += ch; mode = copying; done } for ch in s do match mode with | #copying => handlecopying ch; | #quote => if ch == char "'" do match action.quote with | #ignore-quote => assert false; //current += ch; | #keep-quote => current += ch; mode = copying; | #drop-quote => mode = copying; endmatch; elif ch == char "\\" do match action.escape with | #ignore-escape => current += ch; | #keep-escape => current += ch; mode = escape-quote; | #drop-escape => mode = escape-quote; endmatch; else current += ch; done | #dquote => if ch == char '"' do match action.dquote with | #ignore-dquote => assert false; //current += ch; | #keep-dquote => current += ch; mode = copying; | #drop-dquote => mode = copying; endmatch; elif ch == char "\\" do match action.escape with | #ignore-escape => current += ch; | #keep-escape => current += ch; mode = escape-dquote; | #drop-escape => mode = escape-dquote; endmatch; else current += ch; done | #escape-copying => current += ch; mode = copying; | #escape-quote => current += ch; mode = quote; | #escape-dquote => current += ch; mode = dquote; | #skipping => if ord ch > ' '.char.ord do handlecopying ch; done endmatch; done return (mode=mode, current=current, parsed=state.parsed + result); } } // simplified one shot parser. // ignores mismatched quotes and backslashes. fun respectful_split (action:RespectfulParser::action_t) (s:string) : list[string] = { var state = RespectfulParser::respectful_parse action ( mode=RespectfulParser::skipping, current="", parsed=Empty[string] ) s ; // ignore mismatched quotes and backslashes. match state.mode with | #skipping => ; | _ => &state.parsed <- state.parsed + state.current; endmatch; return state.parsed; } fun respectful_split (s:string) : list[string] => respectful_split ( quote=RespectfulParser::keep-quote, dquote=RespectfulParser::keep-dquote, escape=RespectfulParser::keep-escape ) s ; // OO version of the parser. object respectfulParser (action:RespectfulParser::action_t) = { var state = (mode=RespectfulParser::skipping, current="", parsed=Empty[string]); method proc parse (s:string) { state = RespectfulParser::respectful_parse action state s; } method fun get_parsed () => state.parsed; }
2.20 erase, insert or replace substrings
share/lib/std/strings/string.flx
// Note: pos, length! mutators proc erase: &string * size * size = "$1->erase($2,$3);"; proc insert: &string * size * string = "$1->insert($2,$3);"; proc replace: &string * size * size * string = "$1->replace($2,$3,$4);"; functional fun erase: string * size * size -> string = "::std::string($1).erase($2,$3)"; fun insert: string * size * string -> string = "::std::string($1).insert($2,$3)"; fun replace: string * size * size * string -> string = "::std::string($1).replace($2,$3,$4)";
2.21 search and replace
Search and replace by string.
share/lib/std/strings/string.flx
fun search_and_replace (x:string, var spos:size, s:string, r:string) : string = { val m = s.len; var o = x.[to spos]; var n = (x,s,spos).stl_find; while n != stl_npos do o+=x.[spos to n]+r; spos = n+m; n = (x,s,spos).stl_find.size; done o+=x.[spos to]; return o; } fun search_and_replace (x:string, s:string, r:string) : string => search_and_replace (x,0uz,s,r); fun search_and_replace (vs:list[string * string]) (var v:string) = { match k,b in vs do v = search_and_replace (v,k,b); done return v; }
2.22 Regexp search and replace
Uses Google RE2 engine.
share/lib/std/strings/string.flx
// Replace \0 \1 \2 etc in s with text from v fun subst(s:string, v:varray[StringPiece]): string = { //println$ "Subst " + s +" with " + str v; enum mode_t {cp, ins}; var b = ""; var mode=cp; var j = 0; var count = 0; for var i in 0 upto s.len.int - 1 do match mode with | #cp => if s.[i] == char "\\" do mode = ins; j=0; count = 0; else b += s.[i]; done | #ins => if s.[i] in "0123456789" do j = j * 10 + ord(s.[i]) - ord (char "0"); ++count; else if count == 0 do b += "\\"; elif j < v.len.int do b+= str v.stl_begin.j; done // adjacent insertion? if s.[i] == char "\\" do j=0; count=0; else mode = cp; b += s.[i]; done done endmatch; done // run off end match mode with | #cp => ; | #ins => if count == 0 do b += "\\"; elif j < v.len.int do b+= str v.j; done endmatch; return b; } // Search for regex, replace by r with \0 \1 \2 etc replace by match groups. fun search_and_replace (x:string, var spos: size, re:Re2::RE2, r:string) : string = { var ngroups = re.NumberOfCapturingGroups + 1; var v = varray[StringPiece]$ (ngroups+1).size, StringPiece ""; var o = x.[to spos]; // initial substring var sp = StringPiece(x); var base : +char = sp.data; // base pointer of char array while Re2::Match(re, sp, spos.int, UNANCHORED, v.stl_begin, v.len.int) do var mpos = size(v.0.data - base); // start of match o+= x.[spos to mpos]; // copy upto start of match o+= subst(r,v); // copy replacement spos = mpos + v.0.len; // advance over match done o+=x.[spos to]; // rest of string return o; }
2.23 Parse string to numeric type
share/lib/std/strings/string.flx
fun atoi: string -> int = "::std::atoi($1:postfix.c_str())" requires Cxx_headers::cstdlib; fun atol: string -> long = "::std::atol($1:postfix.c_str())" requires Cxx_headers::cstdlib; fun atoll: string -> long = "::std::atoll($1:postfix.c_str())" requires Cxx_headers::cstdlib; fun atof: string -> double = "::std::atof($1:postfix.c_str())" requires Cxx_headers::cstdlib;
2.24 Reserve store
share/lib/std/strings/string.flx
proc reserve: &string * !ints = "$1->reserve($2);";
2.25 Fetch underlying cstring.
share/lib/std/strings/string.flx
// safely returns a malloc()'d copy, not garbage collected fun _unsafe_cstr: string -> +char = "::flx::rtl::strutil::flx_cstr($1)" is atom; // partially unsafe because the string could be modified. fun stl_begin: &string -> +char = "((char*)$1->c_str())" is atom; fun stl_end: &string -> +char = "((char*)($1->c_str()+$1->size()))" is atom; // this operation returns a char pointer to GC managed storage fun cstr (var s:string) => s.varray[char].stl_begin;
2.26 Polymorphic vsprintf hack
share/lib/std/strings/string.flx
fun vsprintf[t]: +char * t -> string = "::flx::rtl::strutil::flx_asprintf($1,$2)" requires package "flx_strutil" ; fun vsprintf[t]: string * t -> string = "::flx::rtl::strutil::flx_asprintf(const_cast<char*>($1.c_str()),$2)" requires package "flx_strutil" ;
2.27 Case translation
share/lib/std/strings/string.flx
// Convert all characters to upper case fun toupper(s:string):string => map (toupper of char) s; // Convert all characters to lower case fun tolower(s:string):string => map (tolower of char) s; }
2.28 Transation to string
share/lib/std/strings/string.flx
instance Str[string] { fun str (s:string) : string => s; } instance Str[+char] { fun str: +char -> string = '::flx::rtl::strutil::atostr($1)' requires package "flx_strutil"; } instance Repr[string] { fun repr (x:string) : string = { var o = "'"; if len x > 0uz do for var i in 0uz upto (String::len x) - 1uz do o += repr x.[i]; done done return o + "'"; } } open[T in strings] Show[T]; open Set[string,char];