
/* string.q: additional string functions
   $Id: string.q,v 1.4 2007/10/03 22:27:06 agraef Exp $ */

/* This file is part of the Q programming system.

   The Q programming system is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   The Q programming system is distributed in the hope that it will be
   useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

include stdlib;

/* chars. Split a string into a list of individual characters: */

public chars S;
private chars2 I L S;

chars S:String		= chars2 0 (#S) S;

chars2 I L S		= [] if I>=L;
			= [S!I|chars2 (I+1) L S] otherwise;
			
/* join. Concatenate a list of strings, interpolating the given DELIM string
   between each pair of consecutive strings in the list: */

public join DELIM Xs;

join DELIM:String []	= "";
join DELIM:String [X:String]
			= X;
join DELIM:String [X:String|Xs]
			= X++DELIM++join DELIM Xs;

/* split. Split a string into a list of substrings delimited by characters
   in the given DELIM string: */

public split DELIM S;
private split2 DELIM S L I J;

split DELIM:String S:String
			= split2 DELIM S (#S) 0 0;

split2 DELIM S L I J	= []
				if I>=L;
			= split2 DELIM S L I (J+1)
				if (J<L) and then (pos (S!J) DELIM < 0);
			= [substr S I (J-I),""]
				if J=L-1; // trailing delimiter
			= [substr S I (J-I)|split2 DELIM S L (J+1) (J+1)]
				otherwise;

/* strcat. Concatenate a list of strings: */

public strcat Xs;

strcat Xs:List		= foldl (++) "" Xs;

/* mkstr. Create a string consisting of N copies of the given string S: */

public mkstr S N;

mkstr S:String N:Int	= strcat (mklist S N);

/* Overloaded list operations (cf. stdlib.q). */

all P S:String		= all P (chars S);

any P S:String		= any P (chars S);

append S:String C:Char	= S++C;

cat S:String		= chars S;
cat [S:String|Xss]	= cat [chars S|Xss];

cons C:Char S:String	= C++S;

do F S:String		= do F (chars S);

dowith F S1:String S2:String
			= dowith F (chars S1) (chars S2);

dowith3 F S1:String S2:String S3:String
			= dowith3 F (chars S1) (chars S2) (chars S3);

drop N:Int S:String	= sub S N (#S-1);

dropwhile P S:String	= strcat (dropwhile P (chars S));

filter P S:String	= strcat (filter P (chars S));

foldl F A S:String	= foldl F A (chars S);

foldl1 F S:String	= foldl1 F (chars S);

foldr F A S:String	= foldr F A (chars S);

foldr1 F S:String	= foldr1 F (chars S);

hd S:String		= C where C:Char = S!0;

init S:String		= sub S 0 (#S-2) if not null S;

last S:String		= C where C:Char = S!(#S-1);

map F S:String where Xs = map F (chars S):
			= S where S:String = strcat Xs;
			= Xs otherwise;

null ""			= true;
null _:String		= false otherwise;

pop S:String		= sub S 1 (#S-1) if not null S;

push S:String C:Char	= C++S;

reverse S:String	= strcat (reverse (chars S));

scanl F A S:String	= scanl F A (chars S);

scanl1 F S:String	= scanl1 F (chars S);

scanr F A S:String	= scanr F A (chars S);

scanr1 F S:String	= scanr1 F (chars S);

take N:Int S:String	= sub S 0 (N-1);

takewhile P S:String	= strcat (takewhile P (chars S));

tl S:String		= sub S 1 (#S-1) if not null S;

top S:String		= C where C:Char = S!0;

zip S1:String S2:String	= zip (chars S1) (chars S2);

zip3 S1:String S2:String S3:String
			= zip3 (chars S1) (chars S2) (chars S3);

zipwith F S1:String S2:String
			= zipwith F (chars S1) (chars S2);

zipwith3 F S1:String S2:String S3:String
			= zipwith3 F (chars S1) (chars S2) (chars S3);
