Changeset 39136 in project for wiki/eggref/5/srfi-130
- Timestamp:
- 11/07/20 02:42:04 (4 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
wiki/eggref/5/srfi-130
r39135 r39136 1 *SRFI-130: Cursor-based string library2 **Abstract3 [[https://srfi.schemers.org/srfi-130/srfi-130.html#R5RS ][R5RS]] Scheme has an impoverished set of string-processing utilities, which is a problem for authors of portable code. Although [[https://srfi.schemers.org/srfi-130/srfi-130.html#R7RS][R7RS]] provides some extensions and improvements, it is still very incomplete. This SRFI proposes a coherent and comprehensive set of string-processing procedures; it is accompanied by a portable sample implementation of the spec.4 5 This SRFI is derived from SRFI 13. The biggest difference is that it allows subsequences of strings to be specified by cursors as well as the traditional string indexes. In addition, it omits the comparison, case-mapping, and mutation operations of SRFI 13, as well as all procedures already present in [[https://srfi.schemers.org/srfi-130/srfi-130.html#R7RS ][R7RS]].6 7 For more information see: [[https://srfi.schemers.org/srfi-130/ ][SRFI-130: Cursor-based string library]]8 **Procedure Index1 == SRFI-130: Cursor-based string library 2 === Abstract 3 [[https://srfi.schemers.org/srfi-130/srfi-130.html#R5RS|R5RS]] Scheme has an impoverished set of string-processing utilities, which is a problem for authors of portable code. Although [[https://srfi.schemers.org/srfi-130/srfi-130.html#R7RS|R7RS]] provides some extensions and improvements, it is still very incomplete. This SRFI proposes a coherent and comprehensive set of string-processing procedures; it is accompanied by a portable sample implementation of the spec. 4 5 This SRFI is derived from SRFI 13. The biggest difference is that it allows subsequences of strings to be specified by cursors as well as the traditional string indexes. In addition, it omits the comparison, case-mapping, and mutation operations of SRFI 13, as well as all procedures already present in [[https://srfi.schemers.org/srfi-130/srfi-130.html#R7RS|R7RS]]. 6 7 For more information see: [[https://srfi.schemers.org/srfi-130/|SRFI-130: Cursor-based string library]] 8 === Procedure Index 9 9 Here is a list of the procedures provided by this SRFI. 10 ***Cursor operations11 * ***string-cursor?12 * ***string-cursor-start string-cursor-end13 * ***string-cursor-next string-cursor-prev14 * ***string-cursor-forward string-cursor-back15 * ***string-cursor=?16 * ***string-cursor<? string-cursor>?17 * ***string-cursor<=? string-cursor>=?18 * ***string-cursor-diff19 * ***string-cursor->index string-index->cursor20 ***Predicates21 * ***string-null?22 * ***string-every string-any23 ***Constructors24 * ***string-tabulate25 * ***string-unfold string-unfold-right26 ***Conversion27 * ***string->list/cursors string->vector/cursors28 * ***reverse-list->string string-join29 ***Selection30 * ***string-ref/cursor31 * ***substring/cursors string-copy/cursors32 * ***string-take string-take-right33 * ***string-drop string-drop-right34 * ***string-pad string-pad-right35 * ***string-trim string-trim-right string-trim-both36 ***Prefixes & suffixes37 * ***string-prefix-length string-suffix-length38 * ***string-prefix? string-suffix?39 ***Searching40 * ***string-index string-index-right41 * ***string-skip string-skip-right42 * ***string-contains string-contains-right43 ***The whole string44 * ***string-reverse45 * ***string-concatenate string-concatenate-reverse46 * ***string-fold string-fold-right47 * ***string-for-each-cursor48 * ***string-replicate string-count49 * ***string-replace string-split50 * ***string-filter string-remove51 **Rationale10 ==== Cursor operations 11 * string-cursor? 12 * string-cursor-start string-cursor-end 13 * string-cursor-next string-cursor-prev 14 * string-cursor-forward string-cursor-back 15 * string-cursor=? 16 * string-cursor<? string-cursor>? 17 * string-cursor<=? string-cursor>=? 18 * string-cursor-diff 19 * string-cursor->index string-index->cursor 20 ==== Predicates 21 * string-null? 22 * string-every string-any 23 ==== Constructors 24 * string-tabulate 25 * string-unfold string-unfold-right 26 ==== Conversion 27 * string->list/cursors string->vector/cursors 28 * reverse-list->string string-join 29 ==== Selection 30 * string-ref/cursor 31 * substring/cursors string-copy/cursors 32 * string-take string-take-right 33 * string-drop string-drop-right 34 * string-pad string-pad-right 35 * string-trim string-trim-right string-trim-both 36 ==== Prefixes & suffixes 37 * string-prefix-length string-suffix-length 38 * string-prefix? string-suffix? 39 ==== Searching 40 * string-index string-index-right 41 * string-skip string-skip-right 42 * string-contains string-contains-right 43 ==== The whole string 44 * string-reverse 45 * string-concatenate string-concatenate-reverse 46 * string-fold string-fold-right 47 * string-for-each-cursor 48 * string-replicate string-count 49 * string-replace string-split 50 * string-filter string-remove 51 === Rationale 52 52 This SRFI defines a rich set of operations for manipulating strings. These are frequently useful for scripting and other text-manipulation applications. The library's design was influenced by the string libraries found in MIT Scheme, Gambit, RScheme, MzScheme, SLIB, Common Lisp, Bigloo, Guile, Chez, APL, Java, and the SML standard basis. All functionality is available in substring and full-string forms. 53 53 … … 56 56 Unfortunately for this design, Unicode has become much more widely used, and it is now fairly common for implementations to store strings internally as UTF-8 or UTF-16 code unit sequences, which means that indexing operations are potentially O(n) rather than O(1). Using opaque cursors makes it possible to iterate much more efficiently through such strings compared to incrementing or decrementing indexes; however, for backward compatibility, the procedures defined in this SRFI accept either cursors or indexes. The results returned are always cursors: the use of indexes is preserved mainly for the sake of existing code and for implementer convenience. 57 57 58 The operations provided here are entirely independent of the character repertoire supported by the implementation. In particular, this means that the comparison and case conversion procedures of SRFI 13 are excluded. There is also no provision for [[http://www.r6rs.org/final/html/r6rs-lib/r6rs-lib-Z-H-2.html#node_idx_54 ][R6RS normalization procedures]] or for a string->integer procedure that was proposed for SRFI 13 but not included. These may appear in future SRFIs. Furthermore, string mutation can be extremely expensive if the storage used for the string needs to be expanded, particularly if the implementation does not use an indirect pointer to it (as in Chicken), so this SRFI does not provide for it. The low-level procedures of SRFI 13 are specific to the sample implementation, and have been removed to make other implementations simpler and easier.59 60 Many SRFI 13 procedures accept either a predicate, a single character, or a [[https://srfi.schemers.org/srfi-14/srfi-14.html ][SRFI 14]] character set. In this SRFI, only support for predicates is required, though implementations may also support the other two alternatives. In that case, a single character is interpreted as a predicate which returns true if its argument is the same (in the sense of eqv?) to that character; a character set is interpreted as a predicate which returns true if its argument belongs to that character set. In SRFI 13, character sets are inherently more efficient than predicates [[https://srfi.schemers.org/srfi-13/mail-archive/msg00052.html][because testing them is fast and free of side effects]], though how fast character sets actually are if they support full Unicode is very implementation-dependent. The only procedure that absolutely requires character set support, string-tokenize, has been replaced here by the more usual string-split procedure provided by Perl, Python, Java, JavaScript, and other languages.61 62 The search procedures in SRFI 13 return either an index or #fif the search fails. Their counterparts in this SRFI return cursors. Left-to-right searches return a cursor representing the leftmost matching character, or the post-end cursor if there is no match; right-to-left searches return a cursor representing the successor of the rightmost matching character, or the start cursor if there is no match. This convention was devised by Alan Watson and implemented in Chibi Scheme.58 The operations provided here are entirely independent of the character repertoire supported by the implementation. In particular, this means that the comparison and case conversion procedures of SRFI 13 are excluded. There is also no provision for [[http://www.r6rs.org/final/html/r6rs-lib/r6rs-lib-Z-H-2.html#node_idx_54|R6RS normalization procedures]] or for a string->integer procedure that was proposed for SRFI 13 but not included. These may appear in future SRFIs. Furthermore, string mutation can be extremely expensive if the storage used for the string needs to be expanded, particularly if the implementation does not use an indirect pointer to it (as in Chicken), so this SRFI does not provide for it. The low-level procedures of SRFI 13 are specific to the sample implementation, and have been removed to make other implementations simpler and easier. 59 60 Many SRFI 13 procedures accept either a predicate, a single character, or a [[https://srfi.schemers.org/srfi-14/srfi-14.html|SRFI 14]] character set. In this SRFI, only support for predicates is required, though implementations may also support the other two alternatives. In that case, a single character is interpreted as a predicate which returns true if its argument is the same (in the sense of eqv?) to that character; a character set is interpreted as a predicate which returns true if its argument belongs to that character set. In SRFI 13, character sets are inherently more efficient than predicates [[https://srfi.schemers.org/srfi-13/mail-archive/msg00052.html|because testing them is fast and free of side effects]], though how fast character sets actually are if they support full Unicode is very implementation-dependent. The only procedure that absolutely requires character set support, string-tokenize, has been replaced here by the more usual string-split procedure provided by Perl, Python, Java, JavaScript, and other languages. 61 62 The search procedures in SRFI 13 return either an index or {{#f}} if the search fails. Their counterparts in this SRFI return cursors. Left-to-right searches return a cursor representing the leftmost matching character, or the post-end cursor if there is no match; right-to-left searches return a cursor representing the successor of the rightmost matching character, or the start cursor if there is no match. This convention was devised by Alan Watson and implemented in Chibi Scheme. 63 63 64 64 In short, this SRFI is intended to help move the practice of Scheme programming away from mutable strings, string indexes, and SRFI 13, while largely maintaining backward compatibility. It does not require any particular run-time efficiencies from its procedures. 65 **Specification66 ***String cursors67 While indexes are exact integers ranging from 0 to the length of the string they refer to, cursors are opaque objects that point into strings. However, they are not required to belong to a disjoint type, as long as they are either disjoint from indexes or identical to indexes. For example, they may be negative exact integers representing indexes into a byte array underlying the string. It is also possible to implement cursors as a record type or an implementation-specific primitive type. Additionally, in implementations where no provision has been made for cursors, or there is no benefit in implementing them separately because strings are in fact arrays of fixed-length characters, it is useful to allow indexes and cursors to be the same thing. (Cursors must also be disjoint from #f.)68 69 It is an error to make any use of a cursor referring to a string after the string, or any string that shares storage with it, has been mutated by a procedure like string-set!, string-copy!, or string-fill!.70 71 Given a string of length n, there are n + 1valid cursors that refer to it: one for each character in the string, and one for the position just after the last character, known as the "post-end cursor". The cursor for the first (or zeroth) position in the string is known as the "start cursor". The post-end cursor is provided because when creating a string from cursors the second cursor argument is exclusive. It is an error if a cursor argument is not one of the valid cursors for the string argument. The index analogue of the post-end cursor is n.72 ***Calling predicates65 === Specification 66 ==== String cursors 67 While indexes are exact integers ranging from 0 to the length of the string they refer to, cursors are opaque objects that point into strings. However, they are not required to belong to a disjoint type, as long as they are either disjoint from indexes or identical to indexes. For example, they may be negative exact integers representing indexes into a byte array underlying the string. It is also possible to implement cursors as a record type or an implementation-specific primitive type. Additionally, in implementations where no provision has been made for cursors, or there is no benefit in implementing them separately because strings are in fact arrays of fixed-length characters, it is useful to allow indexes and cursors to be the same thing. (Cursors must also be disjoint from {{#f}}.) 68 69 It is an error to make any use of a cursor referring to a string after the string, or any string that shares storage with it, has been mutated by a procedure like {{string-set!}}, {{string-copy!}}, or {{string-fill!}}. 70 71 Given a string of length {{n}}, there are {{n + 1}} valid cursors that refer to it: one for each character in the string, and one for the position just after the last character, known as the "post-end cursor". The cursor for the first (or zeroth) position in the string is known as the "start cursor". The post-end cursor is provided because when creating a string from cursors the second cursor argument is exclusive. It is an error if a cursor argument is not one of the valid cursors for the string argument. The index analogue of the post-end cursor is n. 72 ==== Calling predicates 73 73 All predicates passed to procedures defined in this SRFI may be called in any order and any number of times, except as otherwise noted. This is not the case in SRFI 13. 74 ***Shared storage74 ==== Shared storage 75 75 Some Scheme implementations, e.g. Guile, provide ways to construct substrings that share storage with other strings. SRFI 130 provides only minimal support for such shared substrings. The following SRFI 130 procedures are allowed to return a result which shares storage with one or more of their string arguments: 76 76 77 #+BEGIN_EXAMPLE 78 substring/cursors 79 string-take string-take-right 80 string-drop string-drop-right 81 string-pad string-pad-right 82 string-trim string-trim-right string-trim-both 83 string-split string-filter string-remove 84 #+END_EXAMPLE 85 86 In particular, if the result is the same (in the sense of string=?) as any of the arguments, any implementation of the above procedures may return the string argument without copying it. Other procedures such as string-copy/cursors, as well as all the [[https://srfi.schemers.org/srfi-130/srfi-130.html#R7RS][R7RS]] procedures, are not permitted to return shared results. If a shared value is returned, it may be mutable or immutable. 87 *** Naming conventions 77 substring/cursors 78 string-take string-take-right 79 string-drop string-drop-right 80 string-pad string-pad-right 81 string-trim string-trim-right string-trim-both 82 string-split string-filter string-remove 83 84 In particular, if the result is the same (in the sense of {{string=?}}) as any of the arguments, any implementation of the above procedures may return the string argument without copying it. Other procedures such as {{string-copy/cursors}}, as well as all the [[https://srfi.schemers.org/srfi-130/srfi-130.html#R7RS|R7RS]] procedures, are not permitted to return shared results. If a shared value is returned, it may be mutable or immutable. 85 ==== Naming conventions 88 86 The procedures of this SRFI follow a consistent naming scheme, and are consistent with the conventions developed in SRFI 1. The names are composed of smaller lexemes in a regular way that exposes the structure and relationships between the procedures. This should help the programmer to recall or reconstitute the name of the desired procedure. In particular, the order of common parameters is consistent across the different procedures. 89 87 90 88 Procedures that have left/right directional variants use no suffix to specify left-to-right operation, -right to specify right-to-left operation, and -both to specify both. This is a general convention that has been established in other SRFIs; the value of a convention is proportional to the extent of its use. 91 *** Notation 92 **** In the following procedure specifications: 93 ***** An s parameter is a string. 94 ***** A char parameter is a character. 95 ***** Start and end parameters are half-open string cursors or indexes specifying a substring within a string parameter, and typically restrict a procedure's action to the indicated substring. 96 When omitted, they default to 0 and the length of the string, respectively; or from another point of view, they default to the start cursor and the post-end cursor, respectively. For indexes, it must be the case that 0 <= start <= end <= (string-length s), for the corresponding parameter s when start and end are indexes, and the corresponding relationship must hold when they are cursors. It is an error unless start and end are both cursors or both indexes. 97 ***** A pred parameter is a unary character predicate procedure, returning a true/false value when applied to a character. 98 It is an error if a pred is not pure and functional. 99 ***** A cursor parameter is either a cursor or an exact non-negative integer specifying an index into a string. 100 ***** Len and nchars parameters are exact non-negative integers specifying a length of a string or some number of characters. 101 ***** An obj parameter may be any value at all. 102 **** Passing values to procedures with these parameters that do not satisfy these types is an error. 103 **** Parameters given in square brackets are optional. 104 Unless otherwise noted in the text describing the procedure, any prefix of these optional parameters may be supplied, from zero arguments to the full list. When a procedure returns multiple values, this is shown by listing the return values in square brackets, as well. 105 ***** So, for example, the procedure with signature 106 #+BEGIN_EXAMPLE 107 halts? f [x init-store] â [boolean integer] 108 #+END_EXAMPLE 109 110 would take one (f), two (f, x) or three (f, x, init-store) input parameters, and return two values, a boolean and an integer. 111 **** A parameter followed by "..." means zero or more elements. 112 ***** So the procedure with the signature 113 #+BEGIN_EXAMPLE 114 sum-squares x ... â number 115 #+END_EXAMPLE 116 takes zero or more arguments (x ...), 117 ***** while the procedure with signature 118 #+BEGIN_EXAMPLE 119 spell-check doc dict[1] dict[2] ... â string-list 120 #+END_EXAMPLE 121 122 takes two required parameters (doc and dict[1]) and zero or more optional parameters (dict[2] ...). 123 **** If a procedure's return value is said to be "unspecified," this means that the procedure returns a single arbitrary value. 89 ==== Notation 90 ===== In the following procedure specifications: 91 * An {{s}} parameter is a string. 92 * A {{char}} parameter is a character. 93 * {{Start}} and {{end}} parameters are half-open string cursors or indexes specifying a substring within a string parameter, and typically restrict a procedure's action to the indicated substring. 94 95 When omitted, they default to 0 and the length of the string, respectively; or from another point of view, they default to the start cursor and the post-end cursor, respectively. For indexes, it must be the case that 0 <= {{start}} <= {{end}} <= {{(string-length s)}}, for the corresponding parameter s when {{start}} and {{end}} are indexes, and the corresponding relationship must hold when they are cursors. It is an error unless {{start}} and {{end}} are both cursors or both indexes. 96 * A {{pred}} parameter is a unary character predicate procedure, returning a true/false value when applied to a character. 97 * It is an error if a {{pred}} is not pure and functional. 98 * A cursor parameter is either a cursor or an exact non-negative integer specifying an index into a string. 99 * {{Len}} and {{nchars}} parameters are exact non-negative integers specifying a length of a string or some number of characters. 100 * An {{obj}} parameter may be any value at all. 101 * Passing values to procedures with these parameters that do not satisfy these types is an error. 102 * Parameters given in square brackets are optional. 103 * Unless otherwise noted in the text describing the procedure, any prefix of these optional parameters may be supplied, from zero arguments to the full list. 104 * When a procedure returns multiple values, this is shown by listing the return values in square brackets, as well. 105 ====== So, for example, the procedure with signature 106 {{halts? f [x init-store] â [boolean integer]}} 107 108 would take one {{(f)}}, two {{(f, x)}} or three {{(f, x, init-store)}} input parameters, and return two values, a boolean and an integer. 109 ===== A parameter followed by "..." means zero or more elements. 110 ====== So the procedure with the signature 111 {{sum-squares x ... â number}} 112 113 takes zero or more arguments {{(x ...)}}, 114 ====== while the procedure with signature 115 {{spell-check doc dict[1] dict[2] ... â string-list}} 116 117 takes two required parameters ({{doc}} and {{dict[1]}}) and zero or more optional parameters ({{dict[2]}} ...). 118 ===== If a procedure's return value is said to be "unspecified," this means that the procedure returns a single arbitrary value. 124 119 Such a procedure is not even required to be consistent from call to call. 125 ***Procedures126 ****Cursor operations120 ==== Procedures 121 ===== Cursor operations 127 122 These procedures are mostly taken from Chibi Scheme. 128 ***** string-cursor? obj â boolean 129 Returns #t if obj can be a string cursor, and #f otherwise. In implementations where cursors and indexes are the same thing, #t is returned on any cursor or index; where they are disjoint, #t is returned on cursors, #f on indexes. If obj is neither a cursor nor an index, string-cursor? will always return #f. 130 ***** string-cursor-start s â cursor 131 ***** string-cursor-end s â cursor 123 124 <procedure>string-cursor? obj â boolean</procedure> 125 126 Returns {{#t}} if {{obj}} can be a string cursor, and {{#f}} otherwise. In implementations where cursors and indexes are the same thing, {{#t}} is returned on any cursor or index; where they are disjoint, {{#t}} is returned on cursors, {{#f}} on indexes. If obj is neither a cursor nor an index, string-cursor? will always return {{#f}}. 127 128 <procedure>string-cursor-start s â cursor</procedure> 129 130 131 <procedure>string-cursor-end s â cursor</procedure> 132 132 133 Returns the start/post-end cursor of s respectively. 133 ***** string-cursor-next s cursor â cursor 134 ***** string-cursor-prev s cursor â cursor 134 135 <procedure>string-cursor-next s cursor â cursor</procedure> 136 137 138 <procedure>string-cursor-prev s cursor â cursor</procedure> 139 135 140 Returns the cursor into s following/preceding cursor. If cursor is an index, returns one more/less than cursor. It is an error if cursor is the post-end/start cursor of s. 136 ***** string-cursor-forward s cursor nchars â cursor 137 ***** string-cursor-back s cursor nchars â cursor 138 Returns the cursor into s which follows/precedes cursor by nchars characters. If cursor is an index, returns nchars more/less than cursor. It is an error if the result would be an invalid cursor or index. 139 ***** string-cursor=? cursor[1] cursor[2] â boolean 140 ***** string-cursor<? cursor[1] cursor[2] â boolean 141 ***** string-cursor>? cursor[1] cursor[2] â boolean 142 ***** string-cursor<=? cursor[1] cursor[2] â boolean 143 ***** string-cursor>=? cursor[1] cursor[2] â boolean 141 142 <procedure>string-cursor-forward s cursor nchars â cursor</procedure> 143 144 145 <procedure>string-cursor-back s cursor nchars â cursor</procedure> 146 147 Returns the cursor into s which follows/precedes cursor by {{nchars}} characters. If cursor is an index, returns {{nchars}} more/less than cursor. It is an error if the result would be an invalid cursor or index. 148 149 <procedure>string-cursor=? cursor[1] cursor[2] â boolean</procedure> 150 151 152 <procedure>string-cursor<? cursor[1] cursor[2] â boolean</procedure> 153 154 155 <procedure>string-cursor>? cursor[1] cursor[2] â boolean</procedure> 156 157 158 <procedure>string-cursor<=? cursor[1] cursor[2] â boolean</procedure> 159 160 161 <procedure>string-cursor>=? cursor[1] cursor[2] â boolean</procedure> 162 144 163 Compares two cursors or two indexes pointing into the same string. 145 ***** string-cursor-diff s start end â nchars 146 Returns the number of characters between start and end in string s. Note that the result is always non-negative if start and end are a valid start-end pair. 147 ***** string-cursor->index s cursor â index 148 ***** string-index->cursor s index â cursor 164 165 <procedure>string-cursor-diff s start end â nchars</procedure> 166 167 Returns the number of characters between {{start}} and {{end}} in string s. Note that the result is always non-negative if {{start}} and {{end}} are a valid {{start-end}} pair. 168 169 <procedure>string-cursor->index s cursor â index</procedure> 170 171 172 <procedure>string-index->cursor s index â cursor</procedure> 173 149 174 Converts a cursor/index into s into the corresponding index/cursor. If the argument is already an index/cursor, it is returned unchanged. 150 **** Predicates 151 ***** string-null? s â boolean 175 ===== Predicates 176 177 <procedure>string-null? s â boolean</procedure> 178 152 179 Is s the empty string? 153 ***** string-every pred s [start end] â value 154 ***** string-any pred s [start end] â value 155 Checks to see if every/any character in s satisfies pred proceeding from left (index start) to right (index end). 156 ****** The predicate is "witness-generating": 157 ******* If string-any returns true, the returned true value is the one produced by the application of the predicate. 158 ******* If string-every returns true, the returned true value is the one produced by the final application of the predicate to s[end-1]. 159 If string-every is applied to an empty sequence of characters, it simply returns #t. 160 ****** The names of these procedures do not end with a question mark -- this is to indicate that they do not return a simple boolean (#t or #f), but a general value. 161 **** Constructors 162 ***** string-tabulate proc len â string 163 ****** Proc is an integer â char procedure. 164 ****** Construct a string of size len by applying proc to each value from 0 (inclusive) to len (exclusive) to produce the corresponding string element. 165 ****** The order in which proc is applied to the indexes is not specified. 166 ****** Note that the order of arguments is not the same as SRFI 1's list-tabulate, but is the same as tabulation functions in other SRFIs. 180 181 <procedure>string-every pred s [start end] â value</procedure> 182 183 184 <procedure>string-any pred s [start end] â value</procedure> 185 186 Checks to see if every/any character in s satisfies {{pred}} proceeding from left (index {{start}}) to right (index {{end}}). 187 ======= The predicate is "witness-generating": 188 * If {{string-any}} returns true, the returned true value is the one produced by the application of the predicate. 189 * If {{string-every}} returns true, the returned true value is the one produced by the final application of the predicate to {{s[end-1]}}. 190 If {{string-every}} is applied to an empty sequence of characters, it simply returns {{#t}}. 191 ======= The names of these procedures do not end with a question mark -- this is to indicate that they do not return a simple boolean ({{#t}} or {{#f}}), but a general value. 192 ===== Constructors 193 194 <procedure>string-tabulate proc len â string</procedure> 195 196 * {{Proc}} is an integer â char procedure. 197 * Construct a string of size {{len}} by applying {{proc}} to each value from {{0}} (inclusive) to {{len}} (exclusive) to produce the corresponding string element. 198 * The order in which {{proc}} is applied to the indexes is not specified. 199 * Note that the order of arguments is not the same as SRFI 1's list-tabulate, but is the same as tabulation functions in other SRFIs. 167 200 When this discrepancy was discovered in SRFI 13, it was too late to change SRFI 1. 168 ***** string-unfold stop? mapper successor seed [base make-final] â string 169 ****** This is a fundamental constructor for strings. 170 ****** Successor is used to generate a series of "seed" values from the initial seed: 171 ******* seed, (successor seed), (successor^2 seed), (successor^3 seed), ... 172 ****** Stop? tells us when to stop -- when it returns true when applied to one of these seed values. 173 ****** Mapper maps each seed value to the corresponding character in the result string. These chars are assembled into the string in a left-to-right order. 174 ****** Base is the optional initial/leftmost portion of the constructed string; it defaults to the empty string "". 175 ****** Make-final is applied to the terminal seed value (on which stop? returns true) to produce the final/rightmost portion of the constructed string. It defaults to (lambda (x) ""). 176 ****** string-unfold is a fairly powerful string constructor -- you can use it to convert a list to a string, read a port into a string, reverse a string, copy a string, and so forth. 177 ***** Examples: 178 #+BEGIN_SRC scheme 201 202 <procedure>string-unfold stop? mapper successor seed [base make-final] â string</procedure> 203 204 * This is a fundamental constructor for strings. 205 206 <parameter>Successor</parameter> 207 is used to generate a series of "seed" values from the initial seed: 208 209 seed, (successor seed), (successor^2 seed), (successor^3 seed), ... 210 211 <parameter>Stop?</parameter> 212 tells us when to stop -- when it returns true when applied to one of these seed values. 213 214 <parameter>Mapper</parameter> 215 maps each seed value to the corresponding character in the result string. These chars are assembled into the string in a left-to-right order. 216 217 <parameter>Base</parameter> 218 is the optional initial/leftmost portion of the constructed string; it defaults to the empty string "". 219 220 <parameter>Make-final</parameter> 221 is applied to the terminal seed value (on which stop? returns true) to produce the final/rightmost portion of the constructed string. It defaults to {{(lambda (x) "")}}. 222 223 * {{string-unfold}} is a fairly powerful string constructor -- you can use it to convert a list to a string, read a port into a string, reverse a string, copy a string, and so forth. 224 ====== Examples: 225 <enscript highlight="scheme"> 179 226 (port->string p) = (string-unfold eof-object? values 180 227 (lambda (x) (read-char p)) … … 184 231 185 232 (string-tabulate f size) = (string-unfold (lambda (i) (= i size)) f add1 0) 186 #+END_SRC 187 ******To map f over a list lis, producing a string:188 #+BEGIN_SRC scheme 233 </enscript> 234 ======= To map f over a list lis, producing a string: 235 <enscript highlight="scheme"> 189 236 (string-unfold null? (compose f car) cdr lis) 190 #+END_SRC 191 ******Interested functional programmers may enjoy noting that string-fold-right and string-unfold are in some sense inverses.192 *******That is, given operations knull?, kar, kdr, kons, and knil satisfying193 #+BEGIN_SRC scheme 194 (kons (kar x) (kdr x)) = x and (knull? knil) = #t195 #+END_SRC 196 *******then197 #+BEGIN_SRC scheme 237 </enscript> 238 ======= Interested functional programmers may enjoy noting that string-fold-right and string-unfold are in some sense inverses. 239 ======== That is, given operations knull?, kar, kdr, kons, and knil satisfying 240 <enscript highlight="scheme"> 241 (kons (kar x) (kdr x)) = x and (knull? knil) = {{#t}} 242 </enscript> 243 ======== then 244 <enscript highlight="scheme"> 198 245 (string-fold-right kons knil (string-unfold knull? kar kdr x)) = x 199 #+END_SRC 200 *******and201 #+BEGIN_SRC scheme 246 </enscript> 247 ======== and 248 <enscript highlight="scheme"> 202 249 (string-unfold knull? kar kdr (string-fold-right kons knil s)) = s. 203 #+END_SRC 250 </enscript> 204 251 205 252 The final string constructed does not share storage with either base or the value produced by make-final. 206 253 207 254 This combinator sometimes is called an "anamorphism." 208 ****** Note: implementations should take care that runtime stack limits do not cause overflow when constructing large (e.g., megabyte) strings with string-unfold. 209 ***** string-unfold-right stop? mapper successor seed [base make-final] â string 255 ======= Note: implementations should take care that runtime stack limits do not cause overflow when constructing large (e.g., megabyte) strings with string-unfold. 256 257 <procedure>string-unfold-right stop? mapper successor seed [base make-final] â string</procedure> 258 210 259 This is a fundamental constructor for strings. 211 260 212 261 It is equivalent to string-unfold, except that the results of mapper are assembled into the string in a right-to-left order, base is the optional rightmost portion of the constructed string, and make-final produces the leftmost portion of the constructed string. 213 **** Conversion 214 ***** string->list/cursors s [start end] â char-list 215 ***** string->vector/cursors s [start end] â char-vector 216 string->list/cursors and string->vector/cursors return a newly allocated list or vector of the characters that make up the given string. They differ from the R7RS procedures string->list and string->vector by accepting either cursors or indexes. 217 ***** reverse-list->string char-list â string 218 An efficient implementation of (compose list->string reverse): 219 220 #+BEGIN_SRC scheme 262 ===== Conversion 263 264 <procedure>string->list/cursors s [start end] â char-list</procedure> 265 266 267 <procedure>string->vector/cursors s [start end] â char-vector</procedure> 268 269 {{string->list/cursors}} and {{string->vector/cursors}} return a newly allocated list or vector of the characters that make up the given string. They differ from the R7RS procedures {{string->list}} and {{string->vector}} by accepting either cursors or indexes. 270 ====== reverse-list->string char-list â string 271 An efficient implementation of (compose {{list->string}} reverse): 272 273 <enscript highlight="scheme"> 221 274 (reverse-list->string '(#\a #\B #\c)) â "cBa" 222 #+END_SRC 223 224 This is a common idiom in the epilog of string-processing loops that accumulate an answer in a reverse-order list. (See also string-concatenate-reverse for the "chunked" variant.) 225 ***** string-join string-list [delimiter grammar] â string 275 </enscript> 276 277 This is a common idiom in the epilog of string-processing loops that accumulate an answer in a reverse-order list. (See also {{string-concatenate-reverse}} for the "chunked" variant.) 278 279 <procedure>string-join string-list [delimiter grammar] â string</procedure> 280 226 281 This procedure is a simple unparser --- it pastes strings together using the delimiter string. 227 282 228 The grammar argument is a symbol that determines how the delimiter is used, and defaults to 'infix.229 * ***** 'infix means an infix or separator grammar:insert the delimiter between list elements.283 The {{grammar}} argument is a symbol that determines how the delimiter is used, and defaults to {{'infix}}. 284 * {{'infix}} means an infix or separator {{grammar:}} insert the delimiter between list elements. 230 285 An empty list will produce an empty string -- note, however, that parsing an empty string with an infix or separator grammar is ambiguous. 231 286 Is it an empty list, or a list of one element, the empty string? 232 * ***** 'strict-infixmeans the same as 'infix, but will signal an error if given an empty list.233 * ***** 'suffix means a suffix or terminator grammar:insert the delimiter after every list element. This grammar has no ambiguities.234 * ***** 'prefix means a prefix grammar:insert the delimiter before every list element. This grammar has no ambiguities.235 * *****The delimiter is the string used to delimit elements; it defaults to a single space " ".236 * *****Examples237 #+BEGIN_SRC scheme 287 * {{'strict-infix}} means the same as 'infix, but will signal an error if given an empty list. 288 * {{'suffix}} means a suffix or terminator {{grammar:}} insert the delimiter after every list element. This grammar has no ambiguities. 289 * {{'prefix}} means a prefix {{grammar:}} insert the delimiter before every list element. This grammar has no ambiguities. 290 * The delimiter is the string used to delimit elements; it defaults to a single space " ". 291 * Examples 292 <enscript highlight="scheme"> 238 293 (string-join '("foo" "bar" "baz") ":") => "foo:bar:baz" 239 294 (string-join '("foo" "bar" "baz") ":" 'suffix) => "foo:bar:baz:" … … 246 301 (string-join '() ":" 'suffix) => "" 247 302 (string-join '("") ":" 'suffix) => ":" 248 #+END_SRC 249 ****Selection250 *****string-ref/cursor s cursor â char251 Returns character s[i] using a valid cursor or index of s. It differs from the R7RS procedure string-refby accepting either a cursor or an index.252 *****substring/cursors s start end â string253 *****string-copy/cursors s [start end] â string254 These procedures return a string whose contents are the characters of s beginning with index start (inclusive) and ending with index end (exclusive). If substring/ cursors produces the entire string, it may return either s or a copy of s; in some implementations, proper substrings may share memory with s. However, string-copy /cursors always returns a newly allocated string. They differ from the R7RS procedures substring and string-copy by accepting either cursors or indexes.255 *****string-take s nchars â string256 *****string-drop s nchars â string257 *****string-take-right s nchars â string258 *****string-drop-right s nchars â string259 string-take returns the first nchars of s; string-drop returns all but the first nchars of s. string-take-right returns the last nchars of s; string-drop-right returns all but the last nchars of s.260 261 If these procedures produce the entire string, they may return either s or a copy of s; in some implementations, proper substrings may share memory with s.262 ******Examples263 #+BEGIN_SRC scheme 303 </enscript> 304 ===== Selection 305 ====== string-ref/cursor s cursor â char 306 Returns character {{s[i]}} using a valid cursor or index of {{s}}. It differs from the R7RS procedure {{string-ref}} by accepting either a cursor or an index. 307 ====== substring/cursors s start end â string 308 ====== string-copy/cursors s [start end] â string 309 These procedures return a string whose contents are the characters of s beginning with index {{start}} (inclusive) and ending with index {{end}} (exclusive). If {{substring/cursors}} produces the entire string, it may return either {{s}} or a copy of {{s}}; in some implementations, proper substrings may share memory with {{s}}. However, string-copy /cursors always returns a newly allocated string. They differ from the R7RS procedures substring and string-copy by accepting either cursors or indexes. 310 ====== string-take s nchars â string 311 ====== string-drop s nchars â string 312 ====== string-take-right s nchars â string 313 ====== string-drop-right s nchars â string 314 string-take returns the first {{nchars}} of {{s}}; string-drop returns all but the first {{nchars}} of {{s}}. string-take-right returns the last {{nchars}} of s; string-drop-right returns all but the last {{nchars}} of {{s}}. 315 316 If these procedures produce the entire string, they may return either {{s}} or a copy of {{s}}; in some implementations, proper substrings may share memory with {{s}}. 317 ======= Examples 318 <enscript highlight="scheme"> 264 319 (string-take "Pete Szilagyi" 6) => "Pete S" 265 320 (string-drop "Pete Szilagyi" 6) => "zilagyi" … … 267 322 (string-take-right "Beta rules" 5) => "rules" 268 323 (string-drop-right "Beta rules" 5) => "Beta " 269 #+END_SRC 270 ******It is an error to take or drop more characters than are in the string:271 #+BEGIN_SRC scheme 324 </enscript> 325 ======= It is an error to take or drop more characters than are in the string: 326 <enscript highlight="scheme"> 272 327 (string-take "foo" 37) => error 273 #+END_SRC 274 ***** string-pad s len [char start end] â string 275 ***** string-pad-right s len [char start end] â string 276 Build a string of length len comprised of s padded on the left (right) by as many occurrences of the character char as needed. If s has more than len chars, it is truncated on the left (right) to length len. Char defaults to #\space. 277 278 If len <= end-start, the returned value is allowed to share storage with s, or be exactly s (if len = end-start). 279 280 #+BEGIN_SRC scheme 328 </enscript> 329 330 <procedure>string-pad s len [char start end] â string</procedure> 331 332 333 <procedure>string-pad-right s len [char start end] â string</procedure> 334 335 Build a string of length {{len}} comprised of s padded on the left (right) by as many occurrences of the character char as needed. If {{s}} has more than {{len}} chars, it is truncated on the left (right) to length {{len}}. Char defaults to {{#\space}}. 336 337 If {{len <= end-start}}, the returned value is allowed to share storage with {{s}}, or be exactly {{s}} (if {{len = end-start}}). 338 339 <enscript highlight="scheme"> 281 340 (string-pad "325" 5) => " 325" 282 341 (string-pad "71325" 5) => "71325" 283 342 (string-pad "8871325" 5) => "71325" 284 #+END_SRC 285 ***** string-trim s [pred start end] â string 286 ***** string-trim-right s [pred start end] â string 287 ***** string-trim-both s [pred start end] â string 288 Trim s by skipping over all characters on the left / on the right / on both sides that satisfy the second parameter pred: pred defaults to char-whitespace?. 289 290 If no trimming occurs, these functions may return either s or a copy of s; in some implementations, proper substrings may share memory with s. 291 292 #+BEGIN_SRC scheme 343 </enscript> 344 345 <procedure>string-trim s [pred start end] â string</procedure> 346 347 348 <procedure>string-trim-right s [pred start end] â string</procedure> 349 350 351 <procedure>string-trim-both s [pred start end] â string</procedure> 352 353 Trim {{s}} by skipping over all characters on the left / on the right / on both sides that satisfy the second parameter {{pred}}: {{pred}} defaults to {{char-whitespace?}}. 354 355 If no trimming occurs, these functions may return either {{s}} or a copy of {{s}}; in some implementations, proper substrings may share memory with {{s}}. 356 357 <enscript highlight="scheme"> 293 358 (string-trim-both " The outlook wasn't brilliant, \n\r") 294 359 => "The outlook wasn't brilliant," 295 #+END_SRC 296 **** Prefixes & suffixes 297 ***** string-prefix-length s1 s2 [start1 end1 start2 end2] â integer 298 ***** string-suffix-length s1 s2 [start1 end1 start2 end2] â integer 299 Return the length of the longest common prefix/suffix of the two strings. For prefixes, this is equivalent to the "mismatch index" for the strings (modulo the start cursors). 300 301 The optional start/end cursors or indexes restrict the comparison to the indicated substrings of s1 and s2. 302 ****** Examples 303 #+BEGIN_SRC scheme 304 string-prefix? s1 s2 [start1 end1 start2 end2] â boolean 305 string-suffix? s1 s2 [start1 end1 start2 end2] â boolean 306 #+END_SRC 307 308 Is s1 a prefix/suffix of s2? 309 ****** The optional start/end cursors or indexes restrict the comparison to the indicated substrings of s1 and s2. 310 **** Searching 311 ***** string-index s pred [start end] â cursor 312 ***** string-index-right s pred [start end] â cursor 313 ***** string-skip s pred [start end] â cursor 314 ***** string-skip-right s pred [start end] â cursor 315 string-index searches through s from the left, returning the cursor of the first occurrence of a character which satisfies the predicate pred. If no match is found, it returns end. string-index-right searches through s from the right, returning the cursor of the successor of the first occurrence of a character which satisfies the predicate pred. If no match is found, it returns start. 316 317 The start and end parameters specify the beginning and end cursors or indexes of the search; the search includes the start, but not the end. Be careful of "fencepost" considerations: when searching right-to-left, the first position considered is (string-cursor-prev end), whereas when searching left-to-right, the first index considered is start. That is, the start/end indexes describe the same half-open interval [start,end) in these procedures that they do in all the other SRFI 130 procedures. 318 319 The skip functions are similar, but use the complement of the criteria: they search for the first char that doesn't satisfy pred. E.g., to skip over initial whitespace, say 320 321 #+BEGIN_SRC scheme 360 </enscript> 361 ===== Prefixes & suffixes 362 363 <procedure>string-prefix-length s1 s2 [start1 end1 start2 end2] â integer</procedure> 364 365 366 <procedure>string-suffix-length s1 s2 [start1 end1 start2 end2] â integer</procedure> 367 368 Return the length of the longest common prefix/suffix of the two strings. For prefixes, this is equivalent to the "mismatch index" for the strings (modulo the {{start}} cursors). 369 370 The optional {{start/end}} cursors or indexes restrict the comparison to the indicated substrings of {{s1}} and {{s2}}. 371 372 373 <procedure>string-prefix? s1 s2 [start1 end1 start2 end2] â boolean</procedure> 374 375 376 <procedure>string-suffix? s1 s2 [start1 end1 start2 end2] â boolean</procedure> 377 378 Is {{s1}} a prefix/suffix of {{s2}}? 379 * The optional {{start/end}} cursors or indexes restrict the comparison to the indicated substrings of {{s1}} and {{s2}}. 380 ===== Searching 381 382 <procedure>string-index s pred [start end] â cursor</procedure> 383 384 385 <procedure>string-index-right s pred [start end] â cursor</procedure> 386 387 388 <procedure>string-skip s pred [start end] â cursor</procedure> 389 390 391 <procedure>string-skip-right s pred [start end] â cursor</procedure> 392 393 {{string-index}} searches through {{s}} from the left, returning the cursor of the first occurrence of a character which satisfies the predicate {{pred}}. If no match is found, it returns {{end}}. string-index-right searches through {{s}} from the right, returning the cursor of the successor of the first occurrence of a character which satisfies the predicate {{pred}}. If no match is found, it returns start. 394 395 The {{start}} and {{end}} parameters specify the beginning and end cursors or indexes of the search; the search includes the {{start}}, but not the {{end}}. Be careful of "fencepost" considerations: when searching right-to-left, the first position considered is {{(string-cursor-prev end)}}, whereas when searching left-to-right, the first index considered is start. That is, the {{start/end}} indexes describe the same half-open interval {{[start,end)}} in these procedures that they do in all the other SRFI 130 procedures. 396 397 The skip functions are similar, but use the complement of the criteria: they search for the first char that doesn't satisfy {{pred}}. E.g., to skip over initial whitespace, say 398 399 <enscript highlight="scheme"> 322 400 (substring/cursors s (string-skip s char-whitespace?)) 323 #+END_SRC 324 325 Note that the result is always a cursor, even when start and end are indexes. Use string-cursor->index to convert the result to an index. Therefore, these four functions are not entirely compatible with their SRFI 13 counterparts, which return #fon failure.401 </enscript> 402 403 Note that the result is always a cursor, even when {{start}} and {{end}} are indexes. Use {{string-cursor->index}} to convert the result to an index. Therefore, these four functions are not entirely compatible with their SRFI 13 counterparts, which return {{#f}} on failure. 326 404 327 405 These functions can be trivially composed with string-take and string-drop to produce take-while, drop-while, span, and break procedures without loss of efficiency. 328 ***** string-contains s1 s2 [start1 end1 start2 end2] â cursor 329 ***** string-contains-right s1 s2 [start1 end1 start2 end2] â cursor 330 Does string s1 contain string s2? 331 332 Returns the cursor in s1 referring to the first character of the first/last instance of s2 as a substring, or #f if there is no match. The optional start/end indexes restrict the operation to the indicated substrings. 333 334 The returned cursor is in the range [start1,end1). A successful match must lie entirely in the [start1,end1) range of s1. 335 336 Note that the result is always a cursor, even when start1 and end1 are indexes. Use string-cursor->index to convert a cursor result to an index. 337 338 #+BEGIN_SRC scheme 406 407 <procedure>string-contains s1 s2 [start1 end1 start2 end2] â cursor</procedure> 408 409 410 <procedure>string-contains-right s1 s2 [start1 end1 start2 end2] â cursor</procedure> 411 412 Does string {{s1}} contain string {{s2}}? 413 414 Returns the cursor in {{s1}} referring to the first character of the first/last instance of {{s2}} as a substring, or {{#f}} if there is no match. The optional {{start/end}} indexes restrict the operation to the indicated substrings. 415 416 The returned cursor is in the range {{[start1,end1)}}. A successful match must lie entirely in the {{[start1,end1)}} range of {{s1}}. 417 418 Note that the result is always a cursor, even when {{start1}} and {{end1}} are indexes. Use {{string-cursor->index}} to convert a cursor result to an index. 419 420 <enscript highlight="scheme"> 339 421 (string-contains "eek -- what a geek." "ee" 340 422 12 18) ; Searches "a geek" 341 423 => {Cursor 15} 342 #+END_SRC 343 344 The name of this procedure does not end with a question mark -- this is to indicate that it does not return a simple boolean (#t or #f). Rather, it returns either false (#f) or a cursor. 345 **** The whole string 346 ***** string-reverse s [start end] -> string 424 </enscript> 425 426 The name of this procedure does not end with a question mark -- this is to indicate that it does not return a simple boolean ({{#t}} or {{#f}}). Rather, it returns either false ({{#f}}) or a cursor. 427 ===== The whole string 428 429 <procedure>string-reverse s [start end] -> string</procedure> 430 347 431 Reverse the string. 348 432 349 string-reverse returns the result string and does not alter its sparameter.350 351 #+BEGIN_SRC scheme 433 {{string-reverse}} returns the result string and does not alter its {{s}} parameter. 434 435 <enscript highlight="scheme"> 352 436 (string-reverse "Able was I ere I saw elba.") 353 437 => ".able was I ere I saw elbA" 354 438 (string-reverse "Who stole the spoons?" 14 20) 355 439 => "snoops" 356 #+END_SRC 357 358 Unicode note: Reversing a string simply reverses the sequence of code-points it contains. So a combining diacritic a coming after a base character b in string s would come out before b in the reversed result. 359 ***** string-concatenate string-list â string 440 </enscript> 441 442 Unicode note: Reversing a string simply reverses the sequence of code-points it contains. So a combining diacritic a coming after a base character {{b}} in string {{s}} would come out before {{b}} in the reversed result. 443 444 <procedure>string-concatenate string-list â string</procedure> 445 360 446 Append the elements of string-list together into a single string. Guaranteed to return a freshly allocated string. 361 447 362 448 Note that the (apply string-append string-list) idiom is not robust for long lists of strings, as some Scheme implementations limit the number of arguments that may be passed to an n-ary procedure. 363 ***** string-concatenate-reverse string-list [final-string end] â string 449 450 <procedure>string-concatenate-reverse string-list [final-string end] â string</procedure> 451 364 452 With no optional arguments, this function is equivalent to 365 453 366 #+BEGIN_SRC scheme 454 <enscript highlight="scheme"> 367 455 (string-concatenate (reverse string-list)) 368 #+END_SRC 369 370 If the optional argument final-string is specified, it is consed onto the beginning of string-list before performing the list-reverse and string-concatenateoperations.371 372 If the optional argument end is given, only the characters up to but not including endin final-string are added to the result, thus producing373 374 #+BEGIN_SRC scheme 456 </enscript> 457 458 If the optional argument final-string is specified, it is consed onto the beginning of {{string-list}} before performing the {{list-reverse}} and {{string-concatenate}} operations. 459 460 If the optional argument {{end}} is given, only the characters up to but not including {{end}} in final-string are added to the result, thus producing 461 462 <enscript highlight="scheme"> 375 463 (string-concatenate 376 464 (reverse (cons (substring final-string … … 378 466 end) 379 467 string-list))) 380 #+END_SRC 468 </enscript> 381 469 382 470 E.g. 383 471 384 #+BEGIN_SRC scheme 472 <enscript highlight="scheme"> 385 473 (string-concatenate-reverse '(" must be" "Hello, I") " going.XXXX" 7) 386 474 => "Hello, I must be going." 387 #+END_SRC 475 </enscript> 388 476 389 477 This procedure is useful in the construction of procedures that accumulate character data into lists of string buffers, and wish to convert the accumulated data into a single string when done. 390 ***** string-fold kons knil s [start end] â value 391 ***** string-fold-right kons knil s [start end] â value 478 479 <procedure>string-fold kons knil s [start end] â value</procedure> 480 481 482 <procedure>string-fold-right kons knil s [start end] â value</procedure> 483 392 484 These are the fundamental iterators for strings. 393 485 394 The left-fold operator maps the konsprocedure across the string from left to right395 396 #+BEGIN_SRC scheme 486 The left-fold operator maps the {{kons}} procedure across the string from left to right 487 488 <enscript highlight="scheme"> 397 489 (... (kons s[2] (kons s[1] (kons s[0] knil)))) 398 #+END_SRC 399 400 In other words, string-foldobeys the (tail) recursion401 402 #+BEGIN_SRC scheme 490 </enscript> 491 492 In other words, {{string-fold}} obeys the (tail) recursion 493 494 <enscript highlight="scheme"> 403 495 (string-fold kons knil s start end) = 404 496 (string-fold kons (kons s[start] knil) start+1 end) 405 #+END_SRC 406 407 The right-fold operator maps the konsprocedure across the string from right to left408 409 #+BEGIN_SRC scheme 497 </enscript> 498 499 The {{right-fold}} operator maps the {{kons}} procedure across the string from right to left 500 501 <enscript highlight="scheme"> 410 502 (kons s[0] (... (kons s[end-3] (kons s[end-2] (kons s[end-1] knil))))) 411 #+END_SRC 503 </enscript> 412 504 413 505 obeying the (tail) recursion 414 506 415 #+BEGIN_SRC scheme 507 <enscript highlight="scheme"> 416 508 (string-fold-right kons knil s start end) = 417 509 (string-fold-right kons (kons s[end-1] knil) start end-1) 418 #+END_SRC 419 ******Examples:420 #+BEGIN_SRC scheme 510 </enscript> 511 ======= Examples: 512 <enscript highlight="scheme"> 421 513 ;;; Convert a string to a list of chars. 422 514 (string-fold-right cons '() s) … … 443 535 0 s) 444 536 ans) 445 #+END_SRC 446 ****** The right-fold combinator is sometimes called a "catamorphism." 447 ***** string-for-each-cursor proc s [start end] â unspecified 448 Apply proc to each cursor of s, in order, excluding the post-end cursor. The optional start/end pairs restrict the endpoints of the loop. This is simply a method of looping over a string that is guaranteed to be safe and correct. Example: 449 450 #+BEGIN_SRC scheme 537 </enscript> 538 ======= The right-fold combinator is sometimes called a "catamorphism." 539 540 <procedure>string-for-each-cursor proc s [start end] â unspecified</procedure> 541 542 Apply {{proc}} to each cursor of s, in order, excluding the post-end cursor. The optional {{start/end}} pairs restrict the endpoints of the loop. This is simply a method of looping over a string that is guaranteed to be safe and correct. 543 544 ====== Example: 545 <enscript highlight="scheme"> 451 546 (let ((s "abcde") (v '())) 452 547 (string-for-each-cursor … … 454 549 s) 455 550 v) => (101 100 99 98 97) 456 #+END_SRC 457 ***** string-replicate s from to [start end] â string 551 </enscript> 552 553 <procedure>string-replicate s from to [start end] â string</procedure> 554 458 555 This is an "extended substring" procedure that implements replicated copying of a substring of some string. 459 556 460 S is a string; start and end are optional arguments that demarcate a substring of s, defaulting to 0 and the length of s (i.e., the whole string). Replicate this substring up and down index space, in both the positive and negative directions. For example, if s = "abcdefg", start=3, and end=6, then we have the conceptual bidirectionally-infinite string 461 462 #+BEGIN_EXAMPLE 463 ... d e f d e f d e f d e f d e f d e f d ... 464 ... -9 -8 -7 -6 -5 -4 -3 -2 -1 0 +1 +2 +3 +4 +5 +6 +7 +8 +9 ... 465 #+END_EXAMPLE 466 467 string-replicate returns the substring of this string beginning at index from, and ending at to. Note that these arguments cannot be cursors. It is an error if from is greater than to. 468 ****** You can use string-replicate to perform a variety of tasks: 469 ******* To rotate a string left: (string-replicate "abcdef" 2 8) => "cdefab" 470 ******* To rotate a string right: (string-replicate "abcdef" -2 4) => "efabcd" 471 ******* To replicate a string: (string-replicate "abc" 0 7) => "abcabca" 472 ****** Note that 473 ******* The from/to indexes give a half-open range -- the characters from index from up to, but not including, index to. 474 ******* The from/to indexes are not in terms of the index space for string s. They are in terms of the replicated index space of the substring defined by s, start, and end. 475 ****** It is an error if start=end -- although this is allowed by special dispensation when from=to. 476 ****** Compatibility note: 477 string-replicate is identical to the xsubstring procedure of SRFI 13, except that the to argument is required. 478 ***** string-count s pred [start end] â integer 479 Return a count of the number of characters in s that satisfy the pred argument. 480 ***** string-replace s1 s2 start1 end1 [start2 end2] â string 557 {{S}} is a string; {{start}} and {{end}} are optional arguments that demarcate a substring of {{s}}, defaulting to {{0}} and the length of {{s}} (i.e., the whole string). Replicate this substring up and down index space, in both the positive and negative directions. For example, if {{s = "abcdefg"}}, {{start=3}}, and {{end=6}}, then we have the conceptual bidirectionally-infinite string 558 559 ... d e f d e f d e f d e f d e f d e f d ... 560 ... -9 -8 -7 -6 -5 -4 -3 -2 -1 0 +1 +2 +3 +4 +5 +6 +7 +8 +9 ... 561 562 string-replicate returns the substring of this string beginning at index {{from}}, and ending at {{to}}. Note that these arguments cannot be cursors. It is an error if {{from}} is greater than {{to}}. 563 ======= You can use string-replicate to perform a variety of tasks: 564 * To rotate a string left: 565 <enscript highlight="scheme"> 566 (string-replicate "abcdef" 2 8) => "cdefab 567 </enscript>" 568 * To rotate a string right: 569 <enscript highlight="scheme"> 570 (string-replicate "abcdef" -2 4) => "efabcd 571 </enscript>" 572 * To replicate a string: 573 <enscript highlight="scheme"> 574 (string-replicate "abc" 0 7) => "abcabca 575 </enscript>" 576 ======= Note that 577 * The from/to indexes give a half-open range -- the characters from index from up to, but not including, index to. 578 * The from/to indexes are not in terms of the index space for string {{s}}. They are in terms of the replicated index space of the substring defined by {{s}}, {{start}}, and {{end}}. 579 * It is an error if {{start=end}} -- although this is allowed by special dispensation when from=to. 580 ======= Compatibility note: 581 {{string-replicate}} is identical to the {{xsubstring}} procedure of SRFI 13, except that the to argument is required. 582 583 <procedure>string-count s pred [start end] â integer</procedure> 584 585 Return a count of the number of characters in {{s}} that satisfy the {{pred}} argument. 586 587 <procedure>string-replace s1 s2 start1 end1 [start2 end2] â string</procedure> 588 481 589 Returns 482 590 483 #+BEGIN_SRC scheme 591 <enscript highlight="scheme"> 484 592 (string-append (substring/cursors s1 (string-cursor-start s1) start1) 485 593 (substring/cursors s2 start2 end2) 486 594 (substring/cursors s1 end1 (string-cursor-end s1))) 487 #+END_SRC 488 489 That is, the segment of characters in s1 from start1 to end1 is replaced by the segment of characters in s2 from start2 to end2. If start1=end1, this simply splices the s2 characters into s1at the specified index.490 ******Examples:491 #+BEGIN_SRC scheme 595 </enscript> 596 597 That is, the segment of characters in {{s1}} from {{start1}} to {{end1}} is replaced by the segment of characters in {{s2}} from {{start2}} to end2. If {{start1=end1}}, this simply splices the {{s2}} characters into {{s1}} at the specified index. 598 ======= Examples: 599 <enscript highlight="scheme"> 492 600 (string-replace "The TCL programmer endured daily ridicule." 493 601 "another miserable perl drone" 4 7 8 22 ) => … … 501 609 (string-insert "It's easy to code it up in Scheme." 5 "really ") => 502 610 "It's really easy to code it up in Scheme." 503 #+END_SRC 504 ***** string-split s delimiter [grammar limit start end] â list 505 Returns a list of the words contained in the substring of string from start (inclusive) to end (exclusive). Delimiter specifies a string that is to be used as the word separator. This will often be a single character, but multiple characters are allowed for cases like splitting on "\r\n". The returned list will then have one more item than the number of non-overlapping occurrences of the delimiter in the string. If delimiter is an empty string, then the returned list contains a list of strings, each of which contains a single character. 506 507 Grammar is a symbol with the same meaning as in the string-join procedure. If it is infix, which is the default, processing is done as described above, except that an empty s produces the empty list; if it is strict-infix, an empty s signals an error. The values prefix and suffix cause a leading/trailing empty string in the result to be suppressed. 508 509 If limit is a non-negative exact integer, at most that many splits occur, and the remainder of string is returned as the final element of the list (thus, the result will have at most limit+1 elements). If limit is not specified or is #f, then as many splits as possible are made. It is an error if limit is any other value. 611 </enscript> 612 613 <procedure>string-split s delimiter [grammar limit start end] â list</procedure> 614 615 Returns a list of the words contained in the substring of string from {{start}} (inclusive) to {{end}} (exclusive). Delimiter specifies a string that is to be used as the word separator. This will often be a single character, but multiple characters are allowed for cases like splitting on "\r\n". The returned list will then have one more item than the number of non-overlapping occurrences of the delimiter in the string. If delimiter is an empty string, then the returned list contains a list of strings, each of which contains a single character. 616 617 Grammar is a symbol with the same meaning as in the {{string-join}} procedure. If it is infix, which is the default, processing is done as described above, except that an empty {{s}} produces the empty list; if it is strict-infix, an empty {{s}} signals an error. The values {{prefix}} and {{suffix}} cause a leading/trailing empty string in the result to be suppressed. 618 619 If {{limit}} is a non-negative exact integer, at most that many splits occur, and the remainder of string is returned as the final element of the list (thus, the result will have at most {{limit+1}} elements). If {{limit}} is not specified or is {{#f}}, then as many splits as possible are made. It is an error if {{limit}} is any other value. 510 620 511 621 Use SRFI 115's regexp-split to split on a regular expression rather than a simple string. 512 ***** string-filter pred s [start end] â string 513 ***** string-remove pred s [start end] â string 514 Filter the string s, retaining only those characters that satisfy / do not satisfy pred. 515 516 If the string is unaltered by the filtering operation, these functions may return either s or a copy of s. 517 ****** Compatibility note: 518 string-remove is identical to the string-delete procedure of SRFI 13, but the name string-delete is inconsistent with the conventions of SRFI 1 and other SRFIs. 519 **** Sample implementation 520 This SRFI comes with a sample implementation, which can be found in the repository of this SRFI. It is a cut-down version of the sample implementation of SRFI 13, with the addition of the cursor operations procedures, the */cursors procedures, string-contains-right, and string-split. Here are Olin's original implementation notes: 521 522 I have placed this source on the Net with an unencumbered, "open" copyright. The prefix/suffix and comparison routines in this code had (extremely distant) origins in MIT Scheme's string lib, and were substantially reworked by myself. Being derived from that code, they are covered by the MIT Scheme copyright, which is a generic BSD-style open-source copyright. See the source file for details. 523 524 The KMP string-search code was influenced by implementations written by Stephen Bevan, Brian Denheyer and Will Fitzgerald. However, this version was written from scratch by myself. 525 526 The remainder of the code was written by myself for scsh or for this SRFI; I have placed this code under the scsh copyright, which is also a generic BSD-style open-source copyright. 527 528 The code is written for portability and should be straightforward to port to any Scheme. The source comments contains detailed notes describing the non-R5RS dependencies. 529 530 The library is written for clarity and well-commented. Fast paths are provided for common cases. This is not to say that the implementation can't be tuned up for a specific Scheme implementation. There are notes in the comments addressing ways implementors can tune the reference implementation for performance. 531 532 In short, I've written the reference implementation to make it as painless as possible for an implementor -- or a regular programmer -- to adopt this library and get good results with it. 533 534 Another implementation, derived from Chibi Scheme's SRFI 130, is present in the foof subdirectory. This implementation is smaller but may be slower. It can be more easily adapted to Schemes that differentiate between indexes and cursors. 535 **** Acknowledgements 622 623 <procedure>string-filter pred s [start end] â string</procedure> 624 625 626 <procedure>string-remove pred s [start end] â string</procedure> 627 628 Filter the string {{s}}, retaining only those characters that satisfy / do not satisfy {{pred}}. 629 630 If the string is unaltered by the filtering operation, these functions may return either {{s}} or a copy of {{s}}. 631 ======= Compatibility note: 632 {{string-remove}} is identical to the {{string-delete}} procedure of SRFI 13, but the name {{string-delete}} is inconsistent with the conventions of SRFI 1 and other SRFIs. 633 ===== Sample implementation 634 This SRFI comes with a sample implementation, which can be found in the repository of this SRFI. It is a cut-down version of the sample implementation of SRFI 13, with the addition of the cursor operations procedures, the {{*/cursors}} procedures, {{string-contains-right}}, and {{string-split}}. Here are Olin's original implementation notes: 635 636 ''I have placed this source on the Net with an unencumbered, "open" copyright. The prefix/suffix and comparison routines in this code had (extremely distant) origins in MIT Scheme's string lib, and were substantially reworked by myself. Being derived from that code, they are covered by the MIT Scheme copyright, which is a generic BSD-style open-source copyright. See the source file for details.'' 637 638 ''The KMP string-search code was influenced by implementations written by Stephen Bevan, Brian Denheyer and Will Fitzgerald. However, this version was written from scratch by myself.'' 639 640 ''The remainder of the code was written by myself for scsh or for this SRFI; I have placed this code under the scsh copyright, which is also a generic BSD-style open-source copyright.'' 641 642 ''The code is written for portability and should be straightforward to port to any Scheme. The source comments contains detailed notes describing the non-R5RS dependencies.'' 643 644 ''The library is written for clarity and well-commented. Fast paths are provided for common cases. This is not to say that the implementation can't be tuned up for a specific Scheme implementation. There are notes in the comments addressing ways implementors can tune the reference implementation for performance.'' 645 646 ''In short, I've written the reference implementation to make it as painless as possible for an implementor -- or a regular programmer -- to adopt this library and get good results with it.'' 647 648 ''Another implementation, derived from Chibi Scheme's SRFI 130, is present in the foof subdirectory. This implementation is smaller but may be slower. It can be more easily adapted to Schemes that differentiate between indexes and cursors.'' 649 ===== Acknowledgements 536 650 Thanks to the members of the SRFI 130 mailing list who made this SRFI what it now is, including Per Bothner, Arthur Gleckler, Shiro Kawai, Jim Rees, and especially Alex Shinn, whose idea it was to make cursors and indexes disjoint, and who provided the foof implementation. The following acknowledgements by Olin Shivers are taken from SRFI 13: 537 651 … … 543 657 544 658 During this document's long development period, great patience was exhibited by Mike Sperber, who is the editor for the SRFI, and by Hillary Sullivan, who is not. 545 ****References & links546 *****[CommonLisp]659 ===== References & links 660 ====== [CommonLisp] 547 661 Common Lisp: the Language. 548 662 Guy L. Steele Jr. (editor). … … 552 666 The Common Lisp "HyperSpec," produced by Kent Pitman, is essentially the ANSI spec for Common Lisp: 553 667 http://www.lispworks.com/documentation/HyperSpec/Front/index.htm. 554 *****[MIT-Scheme]668 ====== [MIT-Scheme] 555 669 http://www.swiss.ai.mit.edu/projects/scheme/ 556 *****[R5RS]670 ====== [R5RS] 557 671 Revised^5 report on the algorithmic language Scheme. 558 672 R. Kelsey, W. Clinger, J. Rees (editors). … … 560 674 and ACM SIGPLAN Notices, Vol. 33, No. 9, October, 1998. 561 675 Available at http://www.schemers.org/Documents/Standards/. 562 *****[R7RS]676 ====== [R7RS] 563 677 Revised^7 report on the algorithmic language Scheme. 564 678 A. Shinn, J. Cowan, A. Gleckler (editors). 565 679 Available at http://r7rs.org. 566 *****[SRFI]680 ====== [SRFI] 567 681 The SRFI web site. 568 682 http://srfi.schemers.org/ 569 *****[SRFI-13]683 ====== [SRFI-13] 570 684 SRFI-13: String libraries. 571 685 http://srfi.schemers.org/srfi-13/ 572 *****[SRFI-14]686 ====== [SRFI-14] 573 687 SRFI-14: Character-set library. 574 688 http://srfi.schemers.org/srfi-14/ 575 689 The SRFI 14 char-set library defines a character-set data type, which is used by some procedures in this library. 576 **Author690 === Author 577 691 John Cowan 578 692 Ported and packaged to Chicken 5 by Sergey Goldgaber 579 **Copyright693 === Copyright 580 694 Copyright (C) Olin Shivers (1998, 1999, 2000) and John Cowan (2016). 581 695 … … 585 699 586 700 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 587 **Version history588 ***0.1 - SRFI-130 ported to Chicken 5.2.0701 === Version history 702 ==== 0.1 - SRFI-130 ported to Chicken 5.2.0
Note: See TracChangeset
for help on using the changeset viewer.