home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / ipl / procs / strings.icn < prev    next >
Text File  |  2002-01-24  |  14KB  |  680 lines

  1. ############################################################################
  2. #
  3. #    File:     strings.icn
  4. #
  5. #    Subject:  Procedures for manipulating strings
  6. #
  7. #    Author:   Ralph E. Griswold
  8. #
  9. #    Date:     August 12, 2001
  10. #
  11. ############################################################################
  12. #
  13. #   This file is in the public domain.
  14. #
  15. ############################################################################
  16. #  
  17. #  These procedures perform operations on strings.
  18. #
  19. #    cat(s1, s2, ...)   concatenates an  arbitrary number of strings.
  20. #  
  21. #    charcnt(s, c)       returns the number of instances of characters in
  22. #               c in s.
  23. #
  24. #    collate(s1, s2)    collates the characters of s1 and s2.  For example,
  25. #
  26. #                              collate("abc", "def")
  27. #
  28. #                          produces "adbecf".
  29. #
  30. #    comb(s, i)       generates the combinations of characters from s
  31. #               taken i at a time.
  32. #
  33. #       compress(s, c)     compresses consecutive occurrences of charac-
  34. #                          ters in c that occur in s; c defaults to &cset.
  35. #
  36. #    csort(s)           produces the characters of s in lexical order.
  37. #  
  38. #    decollate(s, i)    produces a string consisting of every other
  39. #                          character of s. If i is odd, the odd-numbered
  40. #                          characters are selected, while if i is even,
  41. #                          the even-numbered characters are selected.
  42. #               The default value of i is 1.
  43. #
  44. #    deletec(s, c)       deletes occurrences of characters in c from s.
  45. #
  46. #    deletep(s, L)       deletes all characters at positions specified in
  47. #               L.
  48. #
  49. #    deletes(s1, s2)    deletes occurrences of s2 in s1.
  50. #
  51. #    diffcnt(s)       returns count of the number of different
  52. #               characters in s.
  53. #
  54. #    extend(s, n)       replicates s to length n.
  55. #
  56. #    fchars(s)       returns characters of s in order of decreasing
  57. #               frequency
  58. #
  59. #    interleave(s1, s2) interleaves characters s2 extended to the length
  60. #               of s1 with s1.
  61. #
  62. #    ispal(s)       succeeds and returns s if s is a palindrome
  63. #
  64. #    maxlen(L, p)       returns the length of the longest string in L.
  65. #               If p is given, it is applied to each string as
  66. #               as a "length" procedure.  The default for p is
  67. #               proc("*", 1).
  68. #
  69. #    meander(s, n)      produces a "meandering" string that contains all
  70. #                          n-tuples of characters of s.
  71. #
  72. #    multicoll(L)       returns the collation of the strings in L.
  73. #
  74. #    ochars(s)          produces the unique characters of s in the order
  75. #               that they first appear in s.
  76. #
  77. #    odd_even(s)       inserts values in a numerical string so that
  78. #               adjacent digits follow an odd-even pattern.
  79. #
  80. #    palins(s, n)       generates all the n-character palindromes from the
  81. #               characters in s.
  82. #
  83. #    permutes(s)        generates all the permutations of the string s.
  84. #
  85. #    pretrim(s, c)       trims characters from beginning of s.
  86. #
  87. #    reflect(s1, i, s2)
  88. #               returns s1 concatenated s2 and the reversal of s1
  89. #               to produce a palindroid; the values of i
  90. #               determine "end conditions" for the reversal:
  91. #
  92. #                0    pattern palindrome; the default
  93. #                1    pattern palindrome with center duplicated
  94. #                2    true palindrome with center not duplicated
  95. #                3    true palindrome with center duplicated
  96. #
  97. #               s2 defaults to the empty string, in which case the
  98. #               result is a full palindrome
  99. #
  100. #       replace(s1, s2, s3)
  101. #               replaces all occurrences of s2 in s1 by s3; fails
  102. #               if s2 is null.
  103. #
  104. #    replacem(s, ...)   performs multiple replacements in the style of
  105. #               of replace(), where multiple argument pairs
  106. #               may be given, as in
  107. #
  108. #                replacem(s, "a", "bc", "d", "cd")
  109. #
  110. #               which replaced all "a"s by "bc"s and all
  111. #               "d"s by "cd"s.  Replacements are performed
  112. #               one after another, not in parallel.
  113. #
  114. #    replc(s, L)       replicates each character of c by the amount
  115. #               given by the values in L.
  116. #  
  117. #       rotate(s, i)       rotates s i characters to the left (negative i
  118. #                          produces rotation to the right); the default
  119. #                          value of i is 1.
  120. #
  121. #    schars(s)          produces the unique characters of s in lexical
  122. #               order.
  123. #
  124. #    scramble(s)       scrambles (shuffles) the characters of s randomly.
  125. #
  126. #    selectp(s, L)       selects characters of s that are at positions
  127. #               given in L.
  128. #
  129. #    slugs(s, n, c)       generates column-sized chunks (length <= n)
  130. #               of string s broken at spans of cset c.
  131. #
  132. #               Defaults:    n    80
  133. #                    c    ' \t\r\n\v\f'
  134. #
  135. #               Example:  every write(">  ", slugs(msg, 50))
  136. #
  137. #    starseq(s)        sequence consisting of the closure of s
  138. #                 starting with the empty string and continuing
  139. #               in lexical order as given in s
  140. #
  141. #    strcnt(s1, s2)       produces a count of the number of non-overlapping
  142. #               times s1 occurs in s2; fails is s1 is null
  143. #
  144. #    substrings(s, i, j)
  145. #               generates all the substrings of s with lengths
  146. #               from i to j, inclusive; i defaults to 1, j
  147. #               to *s
  148. #
  149. #    transpose(s1, s2, s3)
  150. #               transposes s1 according to label s2 and
  151. #               transposition s3.
  152. #  
  153. #    words(s, c)       generates the "words" from the string s that
  154. #               are separated by characters from the cset
  155. #               c, which defaults to ' \t\r\n\v\f'.
  156. #
  157. ############################################################################
  158. #
  159. #  Links:  lists
  160. #
  161. ############################################################################
  162.  
  163. link lists
  164.  
  165. procedure cat(args[])            #: concatenate strings
  166.    local result
  167.  
  168.    result := ""
  169.  
  170.    every result ||:= !args
  171.  
  172.    return result
  173.  
  174. end
  175.  
  176. procedure charcnt(s, c)            #: character count
  177.    local count
  178.  
  179.    count := 0
  180.  
  181.    s ? {
  182.       while tab(upto(c)) do
  183.          count +:= *tab(many(c))
  184.       }
  185.  
  186.    return count
  187.  
  188. end
  189.  
  190. procedure collate(s1, s2)        #: string collation
  191.    local length, ltemp, rtemp
  192.    static llabels, rlabels, clabels, blabels, half
  193.  
  194.    initial {
  195.       llabels := "ab"
  196.       rlabels := "cd"
  197.       blabels := llabels || rlabels
  198.       clabels := "acbd"
  199.       half := 2
  200.       ltemp := left(&cset, *&cset / 2)
  201.       rtemp := right(&cset, *&cset / 2)
  202.       clabels := collate(ltemp, rtemp)
  203.       llabels := ltemp
  204.       rlabels := rtemp
  205.       blabels := string(&cset)
  206.       half := *llabels
  207.       }
  208.  
  209.    length := *s1
  210.    if length <= half then
  211.       return map(left(clabels, 2 * length), left(llabels, length) ||
  212.          left(rlabels, length), s1 || s2)
  213.    else return map(clabels, blabels, left(s1, half) || left(s2, half)) ||
  214.       collate(right(s1, length - half), right(s2, length - half))
  215.  
  216. end
  217.  
  218. procedure comb(s, i)            #: character combinations
  219.    local j
  220.  
  221.    if i < 1 then fail
  222.    suspend if i = 1 then !s
  223.       else s[j := 1 to *s - i + 1] || comb(s[j + 1:0], i - 1)
  224.  
  225. end
  226.  
  227. procedure compress(s, c)        #: character compression
  228.    local result, s1
  229.  
  230.    /c := &cset
  231.  
  232.    result := ""
  233.  
  234.    s ? {
  235.       while result ||:= tab(upto(c)) do {
  236.          result ||:= (s1 := move(1))
  237.          tab(many(s1))
  238.          }
  239.       return result || tab(0)
  240.       }
  241. end
  242.  
  243. procedure csort(s)            #: lexically ordered characters
  244.    local c, s1
  245.  
  246.    s1 := ""
  247.  
  248.    every c := !cset(s) do
  249.       every find(c, s) do
  250.          s1 ||:= c
  251.  
  252.    return s1
  253.  
  254. end
  255.  
  256. #  decollate s according to even or odd i
  257. #
  258. procedure decollate(s, i)        #: string decollation
  259.    local ssize
  260.    static dsize, image, object
  261.  
  262.    initial {
  263.       image := collate(left(&cset, *&cset / 2), left(&cset, *&cset / 2))
  264.       object := left(&cset, *&cset / 2)
  265.       dsize := *image
  266.       }
  267.  
  268.    /i := 1
  269.  
  270.    i %:= 2
  271.    ssize := *s
  272.  
  273.    if ssize + i <= dsize then
  274.       return map(object[1+:(ssize + i) / 2], image[(i + 1)+:ssize], s)
  275.    else return map(object[1+:(dsize - 2) / 2], image[(i + 1)+:dsize - 2],
  276.       s[1+:(dsize - 2)]) || decollate(s[dsize - 1:0], i)
  277.  
  278. end
  279.  
  280. procedure deletec(s, c)            #: delete characters
  281.    local result
  282.  
  283.    result := ""
  284.  
  285.    s ? {
  286.       while result ||:= tab(upto(c)) do
  287.          tab(many(c))
  288.       return result ||:= tab(0)
  289.       }
  290.  
  291. end
  292.  
  293. procedure deletep(s, L)
  294.  
  295.    L := sort(L)
  296.  
  297.    while s[pull(L)] := ""
  298.  
  299.    return s
  300.  
  301. end
  302.  
  303. procedure deletes(s1, s2)        #: delete string
  304.    local result, i
  305.  
  306.    result := ""
  307.    i := *s2
  308.  
  309.    s1 ? {
  310.       while result ||:= tab(find(s2)) do
  311.          move(i)
  312.       return result ||:= tab(0)
  313.       }
  314.          
  315. end
  316.  
  317. procedure diffcnt(s)            #: number of different characters
  318.  
  319.    return *cset(s)
  320.  
  321. end
  322.  
  323. procedure extend(s, n)            #: extend string
  324.    local i
  325.  
  326.    if *s = 0 then fail
  327.  
  328.    i := n / *s
  329.    if n % *s > 0 then i +:= 1
  330.  
  331.    return left(repl(s, i), n)
  332.  
  333. end
  334.  
  335. procedure fchars(s)            #: characters in order of frequency
  336.    local counts, clist, bins, blist, result
  337.  
  338.    counts := table(0)
  339.    every counts[!s] +:= 1
  340.    clist := sort(counts, 4)
  341.  
  342.    bins := table('')
  343.    while bins[pull(clist)] ++:= pull(clist)
  344.    blist := sort(bins, 3)
  345.  
  346.    result := ""
  347.    while result ||:= pull(blist) do
  348.       pull(blist)
  349.  
  350.    return result
  351.  
  352. end
  353.  
  354. procedure interleave(s1, s2)        #: interleave strings
  355.  
  356.    return collate(s1, extend(s2, *s1)) | fail
  357.  
  358. end
  359.  
  360. procedure ispal(s)            #: test for palindrome
  361.  
  362.    if s == reverse(s) then return s else fail
  363.  
  364. end
  365.  
  366. procedure maxlen(L, p)            #: maximum string length
  367.    local i
  368.  
  369.    if *L = 0 then fail
  370.  
  371.    /p := proc("*", 1)
  372.  
  373.    i := 0
  374.  
  375.    every i <:= p(!L)
  376.  
  377.    return i
  378.  
  379. end
  380.  
  381. procedure meander(alpha, n)        #: meandering strings
  382.    local result, trial, t, i, c
  383.  
  384.    i := *alpha
  385.    t := n - 1
  386.    result := repl(alpha[1], t)            # base string
  387.  
  388.    while c := alpha[i] do {            # try a character
  389.       result ? {                # get the potential n-tuple
  390.          tab(-t)
  391.          trial := tab(0) || c
  392.          }
  393.       if result ? find(trial) then         # duplicate, work back
  394.          i -:= 1
  395.       else {
  396.          result ||:= c                # add it
  397.          i := *alpha                # and start from end again
  398.          }
  399.       }
  400.  
  401.    return result[n:0]
  402.  
  403. end
  404.  
  405. procedure multicoll(L)            #: collate strings in list
  406.    local result, i, j
  407.  
  408.    result := ""
  409.  
  410.    every i := 1 to *L[1] do        # no other longer if legal
  411.       every j := 1 to *L do
  412.          result ||:= L[j][i]
  413.  
  414.    return result
  415.  
  416. end
  417.  
  418. procedure ochars(w)            #: first appearance unique characters
  419.    local out, c
  420.  
  421.    out := ""
  422.  
  423.    every c := !w do
  424.     if not find(c, out) then
  425.         out ||:= c
  426.  
  427.    return out
  428.  
  429. end
  430.  
  431. procedure odd_even(s)            #: odd-even numerical string
  432.    local result, i, j
  433.  
  434.    every i := integer(!s) do {
  435.       if /result then result := i
  436.       else if (i % 2) = (j % 2) then result ||:= (j + 1) || i
  437.       else result ||:= i
  438.       j := i
  439.       }
  440.  
  441.    return result
  442.  
  443. end
  444.  
  445. procedure palins(s, n)            #: palindromes
  446.    local c, lpart, mpart, rpart, h, p
  447.  
  448.    if n = 1 then suspend !s
  449.    else if n = 2 then
  450.       every c := !s do suspend c || c
  451.    else if n % 2 = 0 then {        # even
  452.       h := (n - 2) / 2
  453.       every p := palins(s, n - 2) do {
  454.          p ? {
  455.             lpart := move(h)
  456.             rpart := tab(0)
  457.             }
  458.          every c := !s do {
  459.             mpart := c || c
  460.             suspend lpart || mpart || rpart
  461.             }
  462.          }
  463.       }
  464.    else {                # odd
  465.       h := (n - 1) / 2
  466.       every p := palins(s, n - 1) do {
  467.          p ? {
  468.             lpart := move(h)
  469.             rpart := tab(0)
  470.             }
  471.          every suspend lpart || !s || rpart
  472.          }
  473.       }
  474.     
  475. end
  476.  
  477. procedure permutes(s)            #: generate string permutations
  478.    local i
  479.  
  480.    if *s = 0 then return ""
  481.    suspend s[i := 1 to *s] || permutes(s[1:i] || s[i+1:0])
  482.  
  483. end
  484.  
  485. procedure pretrim(s, c)            #: pre-trim string
  486.  
  487.    /c := ' '
  488.  
  489.    s ? {
  490.       tab(many(c))
  491.       return tab(0)
  492.       }
  493.  
  494. end
  495.  
  496. procedure reflect(s1, i, s2)            #: string reflection
  497.  
  498.    /i :=0
  499.    /s2 := ""
  500.  
  501.    return s1 || s2 || reverse(
  502.       case i of {
  503.          0:   s1[2:-1]        # pattern palindrome
  504.          1:   s1[2:0]        # pattern palindrome with first character at end
  505.          2:   s1[1:-1]        # true palindrome with center character unduplicated
  506.          3:   s1        # true palindrome with center character duplicated
  507.          }
  508.       )
  509.  
  510. end
  511.  
  512. procedure replace(s1, s2, s3)        #: string replacement
  513.    local result, i
  514.  
  515.    result := ""
  516.    i := *s2
  517.    if i = 0 then fail            # would loop on empty string
  518.  
  519.    s1 ? {
  520.       while result ||:= tab(find(s2)) do {
  521.          result ||:= s3
  522.          move(i)
  523.          }
  524.       return result || tab(0)
  525.       }
  526.  
  527. end
  528.  
  529. procedure replacem(s, pairs[])        #: multiple string replacement
  530.  
  531.    while s := replace(s, get(pairs), get(pairs))
  532.  
  533.    return s
  534.  
  535. end
  536. procedure replc(s, L)            #: replicate characters
  537.    local result
  538.  
  539.    result := ""
  540.  
  541.    every result ||:= repl(!s, get(L))
  542.  
  543.    return result
  544.  
  545. end
  546.  
  547. procedure rotate(s, i)            #: string rotation
  548.  
  549.    if s == "" then return s
  550.    /i := 1
  551.    if i = 0 then return s
  552.    else if i < 0 then i +:= *s
  553.    i %:= *s
  554.  
  555.    return s[(i + 1):0] || s[1:(i + 1)]
  556.  
  557. end
  558.  
  559. procedure schars(s)            #: lexical unique characters
  560.  
  561.    return string(cset(s))
  562.  
  563. end
  564.  
  565. procedure scramble(s)            #: scramble string
  566.    local i
  567.  
  568.    s := string(s) | fail
  569.  
  570.    every i := *s to 2 by -1 do
  571.       s[?i] :=: s[i]
  572.  
  573.    return s
  574.  
  575. end
  576.  
  577. procedure selectp(s, L)            #: select characters
  578.    local result
  579.  
  580.    result := ""
  581.  
  582.    every result ||:= s[!L]
  583.  
  584.    return result
  585.  
  586. end
  587.  
  588. procedure slugs(s, n, c)          #: generate s in chunks of size <= n
  589.    local i, t
  590.  
  591.    (/n := 80) | (n := 0 < integer(n)) | runerr(101, n)
  592.    /c := ' \t\r\n\v\f'
  593.  
  594.    n +:= 1
  595.    while *s > 0 do s ? {
  596.       if *s <= n then
  597.          return trim(s, c)
  598.       if tab(i := (n >= upto(c))) then {
  599.          tab(many(c))
  600.          while tab(i := (n >= upto(c))) do {
  601.             tab(many(c))
  602.             }
  603.          suspend .&subject[1:i]
  604.          }
  605.       else {
  606.          t := tab(n | 0)
  607.          suspend t
  608.          }
  609.       s := tab(0)
  610.       }
  611.    fail
  612. end
  613.  
  614. procedure starseq(s)        #: closure sequence
  615.  
  616.    /s := ""
  617.  
  618.    suspend "" | (starseq(s) || !s)
  619.  
  620. end
  621.  
  622. procedure strcnt(s1, s2)        #: substring count
  623.    local j, i
  624.  
  625.    if *s1 = 0 then fail            # null string would loop
  626.  
  627.    j := 0
  628.    i := *s1
  629.  
  630.    s2 ? {
  631.       while tab(find(s1)) do {
  632.          j +:= 1
  633.          move(i)
  634.          }
  635.       return j
  636.       }
  637.  
  638. end
  639.  
  640. procedure substrings(s, i, j)        #: generate substrings
  641.  
  642.    /i := 1
  643.    /j := *s
  644.  
  645.    s ? {
  646.       every tab(1 to *s) do
  647.          suspend move(i to j)
  648.       }
  649.  
  650. end
  651.  
  652. procedure transpose(s1, s2, s3)        #: transpose characters
  653.    local n, result
  654.  
  655.    n := *s2
  656.    result := ""
  657.  
  658.    s1 ? {
  659.       while result ||:= map(s3, s2, move(n))
  660.       return result ||:= tab(0)
  661.       }
  662.  
  663. end
  664.  
  665. procedure words(s, c)        #: generate words from string
  666.  
  667.    /c := ' \t\r\n\v\f'
  668.  
  669.    s ? {
  670.       tab(many(c))
  671.       while not pos(0) do {
  672.          suspend tab(upto(c) | 0) \ 1
  673.          tab(many(c))
  674.          }
  675.       }
  676.  
  677.    fail
  678.  
  679. end
  680.