NB. string manipulation

NB. charsub        character substitution
NB. cut            cut text, by default on blanks
NB. cuts           cut y. at x. (conjunction)
NB. deb            delete extra blanks
NB. debc           delete extra blank columns in matrix
NB. dlb            delete leading blanks
NB. dltb           delete leading and trailing blanks
NB. dltbs          delete multiple leading and trailing blanks
NB. dtb            delete trailing blanks
NB. dtbs           delete multiple trailing blanks
NB. delstring      delete occurrences of x. from y.
NB. ljust          left justify
NB. rjust          right justify
NB. rplc           replace in string
NB. ss             string search for x. in y.
NB.
NB. dropafter      drop after x. in y.
NB. dropto         drop to x. in y.
NB. takeafter      take after x. in y.
NB. taketo         take to x. in y.
NB.
NB. stringreplace    replace in string
NB. fstringreplace  replace in file

NB. For example:
NB.
NB.   3       =  'de' # cuts _1 'abcdefg'
NB.   'abcfg' =  'de' delstring 'abcdefg'
NB.   'abcde' =  'de' dropafter 'abcdefg'
NB.   'defg'  =  'de' dropto    'abcdefg'
NB.   'fg'    =  'de' takeafter 'abcdefg'
NB.   'abc'   =  'de' taketo    'abcdefg'

cocurrent 'z'

NB. =========================================================
NB.*cuts v cut y. at x. (conjunction)
NB. string (verb cuts n) text
NB.   n=_1  up to but not including string
NB.   n= 1  up to and including string
NB.   n=_2  after but not including string
NB.   n= 2  after and including string
cuts=: 2 : 0
if. n.=1 do. [: u. (#@[ + E. i. 1:) {. ]
elseif. n.=_1 do. [: u. (E. i. 1:) {. ]
elseif. n.= 2 do. [: u. (E. i. 1:) }. ]
elseif. 1 do. [: u. (#@[ + E. i. 1:) }. ]
end.
)

NB. =========================================================
NB.*cut v cut text, by default on blanks
NB.*deb v delete extra blanks
NB.*dlb v delete leading blanks
NB.*dltb v delete leading and trailing blanks
NB.*dtb v delete trailing blanks
NB.*delstring v delete occurrences of x. from y.
NB.*ljust v left justify
NB.*rjust v right justify
NB.*ss v string search

cut=: ' '&$: :([: -.&a: <;._2@,~)
deb=: #~ (+. 1: |. (> </\))@(' '&~:)
debc=: #~"1 [: (+. (1: |. (> </\))) ' '&(+./ .~:)
delstring=: 4 : ';(x.E.r) <@((#x.)&}.) ;.1 r=. x.,y.'
dlb=: }.~ =&' ' i. 0:
dltb=: #~ [: (+./\ *. +./\.) ' '&~:
dtb=: #~ [: +./\. ' '&~:
ljust=: (|.~ +/@(*./\)@(' '&=))"1
rjust=: (|.~ -@(+/)@(*./\.)@(' '&=))"1
ss=: I. @ E.

NB. =========================================================
NB.*dropafter v drop after x. in y.
NB.*dropto v drop to x. in y.
NB.*takeafter v take after x. in y.
NB.*taketo v take to x. in y.

dropto=: ] cuts 2
dropafter=: ] cuts 1
taketo=: ] cuts _1
takeafter=: ] cuts _2

NB. =========================================================
NB.*charsub v character substitution
NB. characterpairs charsub data
NB. For example:
NB.    '-_$ ' charsub '$123 -456 -789'
NB.  123 _456 _789
NB. Use <rplc> for arbitrary string replacement.
charsub=: 4 : 0
'f t'=. ((#x.)$0 1)<@,&a./.x.
t {~ f i. y.
)

NB. =========================================================
NB.*dltbs v delete multiple leading and trailing blanks
NB. text is delimited by characters in x. with default LF
NB. example:
NB.    < 'A' dltbs ' A abc  def  Ars  A  x y  z  '
NB. +-------------------+
NB. |Aabc  defArsAx y  z|
NB. +-------------------+
dltbs=: LF&$: : (4 : 0)
txt=. ({.x.), y.
a=. txt ~: ' '
b=. (a # txt) e. x.
c=. b +. }. b, 1
d=. ~: /\ a #^:_1 c ~: }: 0, c
}. (a >: d) # txt
)

NB. =========================================================
NB.*dtbs v delete multiple trailing blanks in text
NB. text is delimited by characters in x. with default CRLF
NB. example:
NB.    < 'A' dtbs ' A abc  def  Ars  A  x y  z  '
NB. +----------------------+
NB. |A abc  defArsA  x y  z|
NB. +----------------------+
NB.
NB. Algorithm thanks to Brian Bambrough (JForum Nov 2000)
dtbs=: 3 : 0
CRLF dtbs y.
:
txt=. y. , {.x.
blk=. txt ~: ' '
ndx=. +/\ blk
b=. blk < }. (txt e. x.), 0
msk=. blk >: ndx e. b # ndx
}: msk # txt
)

NB. =========================================================
NB.*rplc v replace characters in text string
NB.
NB. form: text rplc oldnew
NB.   oldnew is a 2-column boxed matrix of old ,. new
NB.   or a vector of same
NB.
NB. replace priority is the same order as oldnew
NB.
NB. Examples:
NB.
NB.    'ababa' rplc 'aba';'XYZT';'ba';'+'
NB. XYZT+
NB.
NB.    'ababa' rplc 'ba';'+';'aba';'XYZT'
NB. a++
rplc=: stringreplace~

NB. =========================================================
NB.*fstringreplace v file string replace
NB. form: (old;new) fstringreplace file
fstringreplace=: 4 : 0
nf=. 'no match found'
y=. boxopen y.
try. size=. 1!:4 y catch. nf return. end.
if. size=0 do. nf return. end.
old=. 1!:1 y
new=. x. stringreplace old
if. old -: new do. nf return. end.
new 1!:2 y
cnt=. +/ (0 pick x.) E. old
(":cnt),' replacement',((1~:cnt)#'s'),' made'
)

NB. =========================================================
NB.*stringreplace v replace characters in text string
NB.
NB. form: oldnew stringreplace tet
NB.   oldnew is a 2-column boxed matrix of old ,. new
NB.   or a vector of same
NB.
NB. stringreplace priority is the same order as oldnew
NB.
NB. Examples:
NB.
NB.    ('aba';'XYZT';'ba';'+') stringreplace 'ababa'
NB. XYZT+
NB.
NB.    ('ba';'+';'aba';'XYZT') stringreplace 'ababa'
NB. a++

stringreplace=: 4 : 0

txt=. ,y.
x=. _2 [\ ,x.
old=. {."1 x
new=. {:"1 x
oldlen=. # &> old
newlen=. # &> new

if. *./ 1 = oldlen do.
  
  hit=. (;old) i. txt
  ndx=. I. hit < #old
  
  if. 0 e. $ndx do. txt return. end.
  
  cnt=. 1
  exp=. hit { newlen,1
  hnx=. ndx { hit
  bgn=. ndx + +/\ 0, (}: hnx) { newlen - 1
  
else.
  
  
  hit=. old I. @ E. each <txt
  cnt=. # &> hit
  
  if. 0 = +/ cnt do. txt return. end.
  
  bgn=. set=. ''
  
  pick=. > @ {
  diff=. }. - }:
  
  for_i. I. 0 < cnt do.
    ln=. i pick oldlen
    cx=. (i pick hit) -. set, ,bgn -/ i.ln
    while. 0 e. b=. 1, <:/\ ln <: diff cx do. cx=. b#cx end.
    hit=. (<cx) i} hit
    bgn=. bgn, cx
    set=. set, ,cx +/ i.ln
  end.
  
  cnt=. # &> hit
  msk=. 0 < cnt
  exp=. (#txt) $ 1
  del=. newlen - oldlen
  
  if. #add=. I. msk *. del > 0 do.
    exp=. (>: (add{cnt) # add{del) (;add{hit) } exp
  end.
  
  if. #sub=. I. msk *. del < 0 do.
    sbx=. ; (;sub{hit) + each (sub{cnt) # i. each sub{del
    exp=. 0 sbx } exp
  end.
  
  hit=. ; hit
  ind=. /: (#hit) $ 1 2 3
  hnx=. (/: ind { hit) { ind    NB. hnx=. /: hit
  bgn=. (hnx { hit) + +/\ 0, }: hnx { cnt # del
  
end.

ind=. ; bgn + each hnx { cnt # i.each newlen
rep=. ; hnx { cnt # new
rep ind} exp # txt
)
