4907 |
4911 |
4908 "Created: 12.5.1996 / 20:09:29 / cg" |
4912 "Created: 12.5.1996 / 20:09:29 / cg" |
4909 "Modified: 17.4.1997 / 12:50:23 / cg" |
4913 "Modified: 17.4.1997 / 12:50:23 / cg" |
4910 ! ! |
4914 ! ! |
4911 |
4915 |
|
4916 |
4912 !CharacterArray methodsFor:'special string converting'! |
4917 !CharacterArray methodsFor:'special string converting'! |
|
4918 |
|
4919 expandPlaceholders:escapeCharacter with:argArrayOrDictionary on:aStream |
|
4920 "this is the generic version of the old %-escaping method, allowing for an arbitrary |
|
4921 escape character to be used (typically $$ or $% are effectively used). |
|
4922 Write the receiver to aStream, where all %i escapes are |
|
4923 replaced by corresponding arguments' printStrings from the argArrayOrDictionary. |
|
4924 I.e. 'hello %1; how is %2' expandPlaceholdersWith:#('world' 'this') results |
|
4925 in the new string 'hello world; how is this'. |
|
4926 As an extension, the argument may also be a dictionary, providing |
|
4927 values for symbolic keys. |
|
4928 In this case, %a .. %z and %(...) are also allowed. |
|
4929 (%1..%9 require a numeric key in the dictionary, however) |
|
4930 To get a '%' character, use a '%%'-escape. |
|
4931 To get an integer-indexed placeHolder followed by another digit, |
|
4932 or an index > 9, you must use %(digit). |
|
4933 See also bindWith:... for VisualAge compatibility. |
|
4934 Use %<cr> to insert a CR and %<tab> to insert a TAB." |
|
4935 |
|
4936 |next v key |
|
4937 idx "{ SmallInteger }" |
|
4938 idx2 "{ SmallInteger }" |
|
4939 start "{ SmallInteger }" |
|
4940 stop "{ SmallInteger }"| |
|
4941 |
|
4942 stop := self size. |
|
4943 start := 1. |
|
4944 [start <= stop] whileTrue:[ |
|
4945 idx := self indexOf:escapeCharacter startingAt:start. |
|
4946 (idx == 0 or:[idx == stop]) ifTrue:[ |
|
4947 aStream nextPutAll:self startingAt:start to:stop. |
|
4948 ^ self. |
|
4949 ]. |
|
4950 "found an escapeCharacter" |
|
4951 aStream nextPutAll:self startingAt:start to:(idx - 1). |
|
4952 next := self at:(idx + 1). |
|
4953 (next == escapeCharacter) ifTrue:[ |
|
4954 aStream nextPut:escapeCharacter. |
|
4955 ] ifFalse:[ |
|
4956 next == $< ifTrue:[ |
|
4957 idx2 := self indexOf:$> startingAt:idx+2. |
|
4958 key := self copyFrom:idx+2 to:idx2-1. |
|
4959 idx := idx2 - 1. |
|
4960 key := key asSymbolIfInterned. |
|
4961 (#(cr tab nl return lf ff null) includesIdentical:key) ifTrue:[ |
|
4962 aStream nextPut:(Character perform:key). |
|
4963 ]. |
|
4964 ] ifFalse:[ |
|
4965 next isDigit ifTrue:[ |
|
4966 v := argArrayOrDictionary at:(next digitValue) ifAbsent:'' |
|
4967 ] ifFalse:[ |
|
4968 next == $( ifTrue:[ |
|
4969 idx2 := self indexOf:$) startingAt:idx+2. |
|
4970 key := self copyFrom:idx+2 to:idx2-1. |
|
4971 idx := idx2 - 1. |
|
4972 (argArrayOrDictionary includesKey:key) ifTrue:[ |
|
4973 v := argArrayOrDictionary at:key |
|
4974 ] ifFalse:[ |
|
4975 key := key asSymbolIfInterned ? key. |
|
4976 (argArrayOrDictionary includesKey:key) ifTrue:[ |
|
4977 v := argArrayOrDictionary at:key |
|
4978 ] ifFalse:[ |
|
4979 (key size == 1 and:[ argArrayOrDictionary includesKey:(key at:1)]) ifTrue:[ |
|
4980 v := argArrayOrDictionary at:(key at:1) |
|
4981 ] ifFalse:[ |
|
4982 key isNumeric ifTrue:[ |
|
4983 key := Integer readFrom:key onError:nil. |
|
4984 ]. |
|
4985 v := argArrayOrDictionary at:key ifAbsent:'' |
|
4986 ] |
|
4987 ]. |
|
4988 ]. |
|
4989 ] ifFalse:[ |
|
4990 (next isLetter and:[argArrayOrDictionary isSequenceable not "is a Dictionary"]) ifTrue:[ |
|
4991 "so next is a non-numeric single character." |
|
4992 v := argArrayOrDictionary |
|
4993 at:next |
|
4994 ifAbsent:[ |
|
4995 "try symbol instead of character" |
|
4996 argArrayOrDictionary |
|
4997 at:next asSymbol |
|
4998 ifAbsent:[String with:escapeCharacter with:next]. |
|
4999 ]. |
|
5000 ] ifFalse:[ |
|
5001 v := String with:$% with:next. |
|
5002 ]. |
|
5003 ] |
|
5004 ]. |
|
5005 "/ v notNil ifTrue:[ |
|
5006 v isBlock ifTrue:[ |
|
5007 v := v value |
|
5008 ]. |
|
5009 |
|
5010 v printOn:aStream. |
|
5011 "/ ]. |
|
5012 ] |
|
5013 ]. |
|
5014 start := idx + 2 |
|
5015 ]. |
|
5016 |
|
5017 " |
|
5018 String streamContents:[:s| |
|
5019 'hello %1' expandPlaceholders:$% with:#('world') on:s. |
|
5020 s cr. |
|
5021 'hello $1; how is $2' expandPlaceholders:$$ with:#('world' 'this') on:s. |
|
5022 s cr. |
|
5023 'hello %2; how is %1' expandPlaceholders:$% with:#('world' 'this') on:s. |
|
5024 s cr. |
|
5025 '%1 plus %2 gives %3 ' expandPlaceholders:$% with:#(4 5 9) on:s. |
|
5026 s cr. |
|
5027 '%%(1)0 gives %(1)0' expandPlaceholders:$% with:#(123) on:s. |
|
5028 s cr. |
|
5029 '%%10 gives %10' expandPlaceholders:$% with:#(123) on:s. |
|
5030 s cr. |
|
5031 '%%(10) gives %(10) %<cr>%<tab>next line' expandPlaceholders:$% with:#(123) on:s. |
|
5032 s cr. |
|
5033 '%test gives %1' expandPlaceholders:$% with:#(123) on:s. |
|
5034 ] |
|
5035 " |
|
5036 |
|
5037 " |
|
5038 |dict| |
|
5039 |
|
5040 dict := Dictionary new. |
|
5041 dict at:1 put:'one'. |
|
5042 dict at:$a put:'AAAAA'. |
|
5043 dict at:$b put:[ Time now ]. |
|
5044 String streamContents:[:s| |
|
5045 'hello $1 $a $b' expandPlaceholders:$$ with:dict on:s. |
|
5046 ]. |
|
5047 " |
|
5048 |
|
5049 "Modified: / 18-11-2010 / 15:43:28 / cg" |
|
5050 ! |
4913 |
5051 |
4914 expandPlaceholdersWith:argArrayOrDictionary |
5052 expandPlaceholdersWith:argArrayOrDictionary |
4915 "return a copy of the receiver, where all %i escapes are |
5053 "return a copy of the receiver, where all %i escapes are |
4916 replaced by corresponding arguments' printStrings from the argArrayOrDictionary. |
5054 replaced by corresponding arguments' printStrings from the argArrayOrDictionary. |
4917 I.e. 'hello %1; how is %2' expandPlaceholdersWith:#('world' 'this') results |
5055 I.e. 'hello %1; how is %2' expandPlaceholdersWith:#('world' 'this') results |
4972 To get an integer-indexed placeHolder followed by another digit, |
5110 To get an integer-indexed placeHolder followed by another digit, |
4973 or an index > 9, you must use %(digit). |
5111 or an index > 9, you must use %(digit). |
4974 See also bindWith:... for VisualAge compatibility. |
5112 See also bindWith:... for VisualAge compatibility. |
4975 Use %<cr> to insert a CR and %<tab> to insert a TAB." |
5113 Use %<cr> to insert a CR and %<tab> to insert a TAB." |
4976 |
5114 |
4977 |next v key |
5115 ^ self expandPlaceholders:$% with:argArrayOrDictionary on:aStream |
4978 idx "{ SmallInteger }" |
|
4979 idx2 "{ SmallInteger }" |
|
4980 start "{ SmallInteger }" |
|
4981 stop "{ SmallInteger }"| |
|
4982 |
|
4983 stop := self size. |
|
4984 start := 1. |
|
4985 [start <= stop] whileTrue:[ |
|
4986 idx := self indexOf:$% startingAt:start. |
|
4987 (idx == 0 or:[idx == stop]) ifTrue:[ |
|
4988 aStream nextPutAll:self startingAt:start to:stop. |
|
4989 ^ self. |
|
4990 ]. |
|
4991 "found a %" |
|
4992 aStream nextPutAll:self startingAt:start to:(idx - 1). |
|
4993 next := self at:(idx + 1). |
|
4994 (next == $%) ifTrue:[ |
|
4995 aStream nextPut:$%. |
|
4996 ] ifFalse:[ |
|
4997 next == $< ifTrue:[ |
|
4998 idx2 := self indexOf:$> startingAt:idx+2. |
|
4999 key := self copyFrom:idx+2 to:idx2-1. |
|
5000 idx := idx2 - 1. |
|
5001 key := key asSymbolIfInterned. |
|
5002 (#(cr tab nl return lf ff null) includesIdentical:key) ifTrue:[ |
|
5003 aStream nextPut:(Character perform:key). |
|
5004 ]. |
|
5005 ] ifFalse:[ |
|
5006 next isDigit ifTrue:[ |
|
5007 v := argArrayOrDictionary at:(next digitValue) ifAbsent:'' |
|
5008 ] ifFalse:[ |
|
5009 next == $( ifTrue:[ |
|
5010 idx2 := self indexOf:$) startingAt:idx+2. |
|
5011 key := self copyFrom:idx+2 to:idx2-1. |
|
5012 idx := idx2 - 1. |
|
5013 (argArrayOrDictionary includesKey:key) ifTrue:[ |
|
5014 v := argArrayOrDictionary at:key |
|
5015 ] ifFalse:[ |
|
5016 key := key asSymbolIfInterned ? key. |
|
5017 (argArrayOrDictionary includesKey:key) ifTrue:[ |
|
5018 v := argArrayOrDictionary at:key |
|
5019 ] ifFalse:[ |
|
5020 (key size == 1 and:[ argArrayOrDictionary includesKey:(key at:1)]) ifTrue:[ |
|
5021 v := argArrayOrDictionary at:(key at:1) |
|
5022 ] ifFalse:[ |
|
5023 key isNumeric ifTrue:[ |
|
5024 key := Integer readFrom:key onError:nil. |
|
5025 ]. |
|
5026 v := argArrayOrDictionary at:key ifAbsent:'' |
|
5027 ] |
|
5028 ]. |
|
5029 ]. |
|
5030 ] ifFalse:[ |
|
5031 (next isLetter and:[argArrayOrDictionary isSequenceable not "is a Dictionary"]) ifTrue:[ |
|
5032 "so next is a non-numeric single character." |
|
5033 v := argArrayOrDictionary |
|
5034 at:next |
|
5035 ifAbsent:[ |
|
5036 "try symbol instead of character" |
|
5037 argArrayOrDictionary |
|
5038 at:next asSymbol |
|
5039 ifAbsent:[String with:$% with:next]. |
|
5040 ]. |
|
5041 ] ifFalse:[ |
|
5042 v := String with:$% with:next. |
|
5043 ]. |
|
5044 ] |
|
5045 ]. |
|
5046 "/ v notNil ifTrue:[ |
|
5047 v isBlock ifTrue:[ |
|
5048 v := v value |
|
5049 ]. |
|
5050 |
|
5051 v printOn:aStream. |
|
5052 "/ ]. |
|
5053 ] |
|
5054 ]. |
|
5055 start := idx + 2 |
|
5056 ]. |
|
5057 |
5116 |
5058 " |
5117 " |
5059 String streamContents:[:s| |
5118 String streamContents:[:s| |
5060 'hello %1' expandPlaceholdersWith:#('world') on:s. |
5119 'hello %1' expandPlaceholdersWith:#('world') on:s. |
5061 s cr. |
5120 s cr. |
5062 'hello %1; how is %2' expandPlaceholdersWith:#('world' 'this') on:s. |
5121 'hello %1; how is %2' expandPlaceholdersWith:#('world' 'this') on:s. |
5063 s cr. |
5122 s cr. |
5064 'hello %2; how is %1' expandPlaceholdersWith:#('world' 'this') on:s. |
5123 'hello %2; how is %1' expandPlaceholdersWith:#('world' 'this') on:s. |
5065 s cr. |
5124 s cr. |
5066 '%1 plus %2 gives %3 ' expandPlaceholdersWith:#(4 5 9) on:s. |
5125 '%1 plus %2 gives %3 ' expandPlaceholdersWith:#(4 5 9) on:s. |
5067 s cr. |
5126 s cr. |
5068 '%%(1)0 gives %(1)0' expandPlaceholdersWith:#(123) on:s. |
5127 '%%(1)0 gives %(1)0' expandPlaceholdersWith:#(123) on:s. |
5069 s cr. |
5128 s cr. |
5070 '%%10 gives %10' expandPlaceholdersWith:#(123) on:s. |
5129 '%%10 gives %10' expandPlaceholdersWith:#(123) on:s. |
5071 s cr. |
5130 s cr. |
5072 '%%(10) gives %(10) %<cr>%<tab>next line' expandPlaceholdersWith:#(123) on:s. |
5131 '%%(10) gives %(10) %<cr>%<tab>next line' expandPlaceholdersWith:#(123) on:s. |
5073 s cr. |
5132 s cr. |
5074 '%test gives %1' expandPlaceholdersWith:#(123) on:s. |
5133 '%test gives %1' expandPlaceholdersWith:#(123) on:s. |
5075 ] |
5134 ] |
5076 " |
5135 " |
5077 |
5136 |
5078 " |
5137 " |
5079 |dict| |
5138 |dict| |