1# Copyright 2001, 2002 Dave Abrahams 2# Copyright 2003 Douglas Gregor 3# Copyright 2003 Rene Rivera 4# Copyright 2002, 2003, 2004, 2005 Vladimir Prus 5# Distributed under the Boost Software License, Version 1.0. 6# (See accompanying file LICENSE_1_0.txt or copy at 7# http://www.boost.org/LICENSE_1_0.txt) 8 9# 10# Returns a list of the following substrings: 11# 1) from beginning till the first occurrence of 'separator' or till the end, 12# 2) between each occurrence of 'separator' and the next occurrence, 13# 3) from the last occurrence of 'separator' till the end. 14# If no separator is present, the result will contain only one element. 15# 16 17rule split ( string separator ) 18{ 19 local result ; 20 local s = $(string) ; 21 22 # Break pieaces off 's' until it has no separators left. 23 local match = 1 ; 24 while $(match) 25 { 26 match = [ MATCH ^(.*)($(separator))(.*) : $(s) ] ; 27 if $(match) 28 { 29 match += "" ; # in case 3rd item was empty - works around MATCH bug 30 result = $(match[3]) $(result) ; 31 s = $(match[1]) ; 32 } 33 } 34 # Combine the remaining part at the beginning, which does not have 35 # separators, with the pieces broken off. Note that the rule's signature 36 # does not allow the initial s to be empty. 37 return $(s) $(result) ; 38} 39 40if [ HAS_NATIVE_RULE regex : split : 1 ] 41{ 42 NATIVE_RULE regex : split ; 43} 44 45# Returns the concatenated results of Applying regex.split to every element of 46# the list using the separator pattern. 47# 48rule split-list ( list * : separator ) 49{ 50 local result ; 51 for s in $(list) 52 { 53 result += [ split $(s) $(separator) ] ; 54 } 55 return $(result) ; 56} 57 58 59# Match string against pattern, and return the elements indicated by indices. 60# 61rule match ( pattern : string : indices * ) 62{ 63 indices ?= 1 2 3 4 5 6 7 8 9 ; 64 local x = [ MATCH $(pattern) : $(string) ] ; 65 return $(x[$(indices)]) ; 66} 67 68 69# Matches all elements of 'list' against the 'pattern' and returns a list of 70# elements indicated by indices of all successful matches. If 'indices' is 71# omitted returns a list of first parenthesised groups of all successful 72# matches. 73# 74rule transform ( list * : pattern : indices * ) 75{ 76 indices ?= 1 ; 77 local result ; 78 for local e in $(list) 79 { 80 local m = [ MATCH $(pattern) : $(e) ] ; 81 if $(m) 82 { 83 result += $(m[$(indices)]) ; 84 } 85 } 86 return $(result) ; 87} 88 89NATIVE_RULE regex : transform ; 90 91 92# Escapes all of the characters in symbols using the escape symbol escape-symbol 93# for the given string, and returns the escaped string. 94# 95rule escape ( string : symbols : escape-symbol ) 96{ 97 local result = "" ; 98 local m = 1 ; 99 while $(m) 100 { 101 m = [ MATCH "^([^$(symbols)]*)([$(symbols)])(.*)" : $(string) ] ; 102 if $(m) 103 { 104 m += "" ; # Supposedly a bug fix; borrowed from regex.split 105 result = "$(result)$(m[1])$(escape-symbol)$(m[2])" ; 106 string = $(m[3]) ; 107 } 108 } 109 string ?= "" ; 110 result = "$(result)$(string)" ; 111 return $(result) ; 112} 113 114 115# Replaces occurrences of a match string in a given string and returns the new 116# string. The match string can be a regex expression. 117# 118rule replace ( 119 string # The string to modify. 120 match # The characters to replace. 121 replacement # The string to replace with. 122 ) 123{ 124 local result = "" ; 125 local parts = 1 ; 126 while $(parts) 127 { 128 parts = [ MATCH ^(.*)($(match))(.*) : $(string) ] ; 129 if $(parts) 130 { 131 parts += "" ; 132 result = "$(replacement)$(parts[3])$(result)" ; 133 string = $(parts[1]) ; 134 } 135 } 136 string ?= "" ; 137 result = "$(string)$(result)" ; 138 return $(result) ; 139} 140 141if [ HAS_NATIVE_RULE regex : replace : 1 ] 142{ 143 NATIVE_RULE regex : replace ; 144} 145 146 147# Replaces occurrences of a match string in a given list of strings and returns 148# a list of new strings. The match string can be a regex expression. 149# 150# list - the list of strings to modify. 151# match - the search expression. 152# replacement - the string to replace with. 153# 154rule replace-list ( list * : match : replacement ) 155{ 156 local result ; 157 for local e in $(list) 158 { 159 result += [ replace $(e) $(match) $(replacement) ] ; 160 } 161 return $(result) ; 162} 163 164 165rule __test__ ( ) 166{ 167 import assert ; 168 169 assert.result a b c : split "a/b/c" / ; 170 assert.result "" a b c : split "/a/b/c" / ; 171 assert.result "" "" a b c : split "//a/b/c" / ; 172 assert.result "" a "" b c : split "/a//b/c" / ; 173 assert.result "" a "" b c "" : split "/a//b/c/" / ; 174 assert.result "" a "" b c "" "" : split "/a//b/c//" / ; 175 assert.result "" a b c "" : split "abc" "" ; 176 assert.result "" "" : split "" "" ; 177 178 assert.result a c b d 179 : match (.)(.)(.)(.) : abcd : 1 3 2 4 ; 180 181 assert.result a b c d 182 : match (.)(.)(.)(.) : abcd ; 183 184 assert.result ababab cddc 185 : match "((ab)*)([cd]+)" : abababcddc : 1 3 ; 186 187 assert.result a.h c.h 188 : transform <a.h> \"b.h\" <c.h> : <(.*)> ; 189 190 assert.result a.h b.h c.h 191 : transform <a.h> \"b.h\" <c.h> : "<([^>]*)>|\"([^\"]*)\"" : 1 2 ; 192 193 assert.result "^<?xml version=\"1.0\"^>" 194 : escape "<?xml version=\"1.0\">" : "&|()<>^" : "^" ; 195 196 assert.result "<?xml version=\\\"1.0\\\">" 197 : escape "<?xml version=\"1.0\">" : "\\\"" : "\\" ; 198 199 assert.result "string string " : replace "string string " " " " " ; 200 assert.result " string string" : replace " string string" " " " " ; 201 assert.result "string string" : replace "string string" " " " " ; 202 assert.result "-" : replace "&" "&" "-" ; 203 assert.result "x" : replace "" "" "x" ; 204 assert.result "xax" : replace "a" "" "x" ; 205 assert.result "xaxbx" : replace "ab" "" "x" ; 206 207 assert.result "-" "a-b" : replace-list "&" "a&b" : "&" : "-" ; 208} 209