CharacterArray.st
changeset 8874 f1fdda306d51
parent 8862 6f550a144c6a
child 8875 1d326cc89ff9
equal deleted inserted replaced
8873:eecab5af2679 8874:f1fdda306d51
    39 documentation
    39 documentation
    40 "
    40 "
    41     CharacterArray is a superclass for all kinds of Strings (i.e.
    41     CharacterArray is a superclass for all kinds of Strings (i.e.
    42     (singleByte-)Strings, TwoByteStrings and whatever comes in the future.
    42     (singleByte-)Strings, TwoByteStrings and whatever comes in the future.
    43 
    43 
    44     This class is abstract, meaning that there are no instances of it. 
    44     This class is abstract, meaning that there are no instances of it.
    45     All this class does is provide common protocol for concrete subclasses.
    45     All this class does is provide common protocol for concrete subclasses.
    46 
    46 
    47     [author:]
    47     [author:]
    48         Claus Gittinger
    48 	Claus Gittinger
    49 
    49 
    50     [see also:]
    50     [see also:]
    51         String TwoByteString
    51 	String TwoByteString
    52         StringCollection
    52 	StringCollection
    53 "
    53 "
    54 ! !
    54 ! !
    55 
    55 
    56 !CharacterArray class methodsFor:'initialization'!
    56 !CharacterArray class methodsFor:'initialization'!
    57 
    57 
    58 initialize
    58 initialize
    59     DecodingFailedSignal isNil ifTrue:[    
    59     DecodingFailedSignal isNil ifTrue:[
    60         DecodingFailedSignal := DecodingError.
    60 	DecodingFailedSignal := DecodingError.
    61         DecodingFailedSignal notifierString:'error during decode'.
    61 	DecodingFailedSignal notifierString:'error during decode'.
    62 
    62 
    63         EncodingFailedSignal :=EncodingError.
    63 	EncodingFailedSignal :=EncodingError.
    64         EncodingFailedSignal notifierString:'error during encode'.
    64 	EncodingFailedSignal notifierString:'error during encode'.
    65     ]
    65     ]
    66 
    66 
    67     "
    67     "
    68      CharacterArray initialize
    68      CharacterArray initialize
    69     "
    69     "
    87     |mySize nBytes newString dstIdx|
    87     |mySize nBytes newString dstIdx|
    88 
    88 
    89     nBytes := aByteCollection size.
    89     nBytes := aByteCollection size.
    90     mySize := self basicNew bitsPerCharacter.
    90     mySize := self basicNew bitsPerCharacter.
    91     mySize == 16 ifTrue:[
    91     mySize == 16 ifTrue:[
    92         newString := self basicNew:(nBytes // 2).
    92 	newString := self basicNew:(nBytes // 2).
    93         dstIdx := 1.
    93 	dstIdx := 1.
    94         aByteCollection pairWiseDo:[:hi :lo |
    94 	aByteCollection pairWiseDo:[:hi :lo |
    95             newString at:dstIdx put:(Character value:(hi bitShift:8)+lo).
    95 	    newString at:dstIdx put:(Character value:(hi bitShift:8)+lo).
    96             dstIdx := dstIdx + 1
    96 	    dstIdx := dstIdx + 1
    97         ].
    97 	].
    98         ^ newString.
    98 	^ newString.
    99     ].
    99     ].
   100 
   100 
   101     ^ (self basicNew:nBytes) replaceFrom:1 with:aByteCollection
   101     ^ (self basicNew:nBytes) replaceFrom:1 with:aByteCollection
   102 
   102 
   103     "
   103     "
   132 
   132 
   133     |newString first|
   133     |newString first|
   134 
   134 
   135     newString := ''.
   135     newString := ''.
   136     first := true.
   136     first := true.
   137     aCollectionOfStrings do:[:s | 
   137     aCollectionOfStrings do:[:s |
   138 	first ifFalse:[
   138 	first ifFalse:[
   139 	    newString := newString , aSeparatorString
   139 	    newString := newString , aSeparatorString
   140 	] ifTrue:[
   140 	] ifTrue:[
   141 	    first := false
   141 	    first := false
   142 	].
   142 	].
   159      This only handles up-to 16bit characters"
   159      This only handles up-to 16bit characters"
   160 
   160 
   161     ^ self decodeFromUTF8:aByteCollection.
   161     ^ self decodeFromUTF8:aByteCollection.
   162 
   162 
   163     "
   163     "
   164      CharacterArray fromUTF8Bytes:#[ 16r41 16r42 ]      
   164      CharacterArray fromUTF8Bytes:#[ 16r41 16r42 ]
   165      CharacterArray fromUTF8Bytes:#[ 16rC1 16r02 ]      
   165      CharacterArray fromUTF8Bytes:#[ 16rC1 16r02 ]
   166      CharacterArray fromUTF8Bytes:#[ 16rE0 16r81 16r02 ]      
   166      CharacterArray fromUTF8Bytes:#[ 16rE0 16r81 16r02 ]
   167      CharacterArray fromUTF8Bytes:#[ 16rEF 16rBF 16rBF ]
   167      CharacterArray fromUTF8Bytes:#[ 16rEF 16rBF 16rBF ]
   168 
   168 
   169    rfc2279 examples:
   169    rfc2279 examples:
   170      CharacterArray fromUTF8Bytes:#[ 16r41 16rE2 16r89 16rA2 16rCE 16r91 16r2E ]      
   170      CharacterArray fromUTF8Bytes:#[ 16r41 16rE2 16r89 16rA2 16rCE 16r91 16r2E ]
   171      CharacterArray fromUTF8Bytes:#[ 16rED 16r95 16r9C 16rEA 16rB5 16rAD 16rEC 16r96 16rB4 ]      
   171      CharacterArray fromUTF8Bytes:#[ 16rED 16r95 16r9C 16rEA 16rB5 16rAD 16rEC 16r96 16rB4 ]
   172      CharacterArray fromUTF8Bytes:#[ 16rE6 16r97 16rA5 16rE6 16r9C 16rAC 16rE8 16rAA 16r9E ]      
   172      CharacterArray fromUTF8Bytes:#[ 16rE6 16r97 16rA5 16rE6 16r9C 16rAC 16rE8 16rAA 16r9E ]
   173 
   173 
   174    invalid:
   174    invalid:
   175      CharacterArray fromUTF8Bytes:#[ 16rC0 16r80 ]      
   175      CharacterArray fromUTF8Bytes:#[ 16rC0 16r80 ]
   176      CharacterArray fromUTF8Bytes:#[ 16rE0 16r80 16r80 ]      
   176      CharacterArray fromUTF8Bytes:#[ 16rE0 16r80 16r80 ]
   177     "
   177     "
   178 !
   178 !
   179 
   179 
   180 new
   180 new
   181     "return a new empty string"
   181     "return a new empty string"
   232      This only handles up-to 16bit characters."
   232      This only handles up-to 16bit characters."
   233 
   233 
   234     ^ CharacterEncoderImplementations::ISO10646_to_UTF8 decodeString:aStringOrByteCollection
   234     ^ CharacterEncoderImplementations::ISO10646_to_UTF8 decodeString:aStringOrByteCollection
   235 
   235 
   236     "
   236     "
   237      CharacterArray fromUTF8Bytes:#[ 16r41 16r42 ]      
   237      CharacterArray fromUTF8Bytes:#[ 16r41 16r42 ]
   238      CharacterArray fromUTF8Bytes:#[ 16rC1 16r02 ]      
   238      CharacterArray fromUTF8Bytes:#[ 16rC1 16r02 ]
   239      CharacterArray fromUTF8Bytes:#[ 16rE0 16r81 16r02 ]      
   239      CharacterArray fromUTF8Bytes:#[ 16rE0 16r81 16r02 ]
   240      CharacterArray fromUTF8Bytes:#[ 16rEF 16rBF 16rBF ]
   240      CharacterArray fromUTF8Bytes:#[ 16rEF 16rBF 16rBF ]
   241 
   241 
   242    rfc2279 examples:
   242    rfc2279 examples:
   243      CharacterArray fromUTF8Bytes:#[ 16r41 16rE2 16r89 16rA2 16rCE 16r91 16r2E ]      
   243      CharacterArray fromUTF8Bytes:#[ 16r41 16rE2 16r89 16rA2 16rCE 16r91 16r2E ]
   244      CharacterArray fromUTF8Bytes:#[ 16rED 16r95 16r9C 16rEA 16rB5 16rAD 16rEC 16r96 16rB4 ]      
   244      CharacterArray fromUTF8Bytes:#[ 16rED 16r95 16r9C 16rEA 16rB5 16rAD 16rEC 16r96 16rB4 ]
   245      CharacterArray fromUTF8Bytes:#[ 16rE6 16r97 16rA5 16rE6 16r9C 16rAC 16rE8 16rAA 16r9E ]      
   245      CharacterArray fromUTF8Bytes:#[ 16rE6 16r97 16rA5 16rE6 16r9C 16rAC 16rE8 16rAA 16r9E ]
   246 
   246 
   247    invalid:
   247    invalid:
   248      CharacterArray fromUTF8Bytes:#[ 16rC0 16r80 ]      
   248      CharacterArray fromUTF8Bytes:#[ 16rC0 16r80 ]
   249      CharacterArray fromUTF8Bytes:#[ 16rE0 16r80 16r80 ]      
   249      CharacterArray fromUTF8Bytes:#[ 16rE0 16r80 16r80 ]
   250     "
   250     "
   251 ! !
   251 ! !
   252 
   252 
   253 !CharacterArray class methodsFor:'pattern matching'!
   253 !CharacterArray class methodsFor:'pattern matching'!
   254 
   254 
   262 matchScan:matchScanArray from:matchStart to:matchStop with:aString from:start to:stop ignoreCase:ignoreCase
   262 matchScan:matchScanArray from:matchStart to:matchStop with:aString from:start to:stop ignoreCase:ignoreCase
   263     "helper for match; return true if the characters from start to stop in
   263     "helper for match; return true if the characters from start to stop in
   264      aString are matching the scan in matchScan from matchStart to matchStop.
   264      aString are matching the scan in matchScan from matchStart to matchStop.
   265      The matchScan is as created by asMatchScanArray.
   265      The matchScan is as created by asMatchScanArray.
   266 
   266 
   267      This algorithm is not at all the most efficient; 
   267      This algorithm is not at all the most efficient;
   268      for heavy duty pattern matching, an interface (primitive) to the regex 
   268      for heavy duty pattern matching, an interface (primitive) to the regex
   269      pattern matching package should be added."
   269      pattern matching package should be added."
   270 
   270 
   271     |matchEntry 
   271     |matchEntry
   272      mStart "{ Class: SmallInteger }"
   272      mStart "{ Class: SmallInteger }"
   273      mStop  "{ Class: SmallInteger }"
   273      mStop  "{ Class: SmallInteger }"
   274      sStart "{ Class: SmallInteger }"
   274      sStart "{ Class: SmallInteger }"
   275      sStop  "{ Class: SmallInteger }"
   275      sStop  "{ Class: SmallInteger }"
   276      mSize  "{ Class: SmallInteger }"
   276      mSize  "{ Class: SmallInteger }"
   283     mStop := matchStop.
   283     mStop := matchStop.
   284     sStart := start.
   284     sStart := start.
   285     sStop := stop.
   285     sStop := stop.
   286 
   286 
   287     [true] whileTrue:[
   287     [true] whileTrue:[
   288 "/ Transcript showCR:('match: ''' , (aString copyFrom:sStart to:sStop) , 
   288 "/ Transcript showCR:('match: ''' , (aString copyFrom:sStart to:sStop) ,
   289 "/                    ''' against:' , (matchScanArray copyFrom:mStart to:mStop) printString).
   289 "/                    ''' against:' , (matchScanArray copyFrom:mStart to:mStop) printString).
   290 
   290 
   291         mSize := mStop - mStart + 1.
   291 	mSize := mStop - mStart + 1.
   292         sSize := sStop - sStart + 1.
   292 	sSize := sStop - sStart + 1.
   293 
   293 
   294         "empty strings match"
   294 	"empty strings match"
   295         (mSize == 0) ifTrue:[^ (sSize == 0)].
   295 	(mSize == 0) ifTrue:[^ (sSize == 0)].
   296 
   296 
   297         matchEntry := matchScanArray at:mStart.
   297 	matchEntry := matchScanArray at:mStart.
   298 
   298 
   299         "/ the most common case first:
   299 	"/ the most common case first:
   300         (sSize ~~ 0 
   300 	(sSize ~~ 0
   301         and:[(checkChar := (aString at:sStart)) = matchEntry]) ifTrue:[
   301 	and:[(checkChar := (aString at:sStart)) = matchEntry]) ifTrue:[
   302             "advance by one and continue"
   302 	    "advance by one and continue"
   303             mStart := mStart + 1.
   303 	    mStart := mStart + 1.
   304             sStart := sStart + 1
   304 	    sStart := sStart + 1
   305         ] ifFalse:[
   305 	] ifFalse:[
   306             (matchEntry == #any) ifTrue:[
   306 	    (matchEntry == #any) ifTrue:[
   307                 "restString empty -> no match"
   307 		"restString empty -> no match"
   308                 (sSize == 0) ifTrue:[^ false].
   308 		(sSize == 0) ifTrue:[^ false].
   309                 "# matches single character"
   309 		"# matches single character"
   310                 ((sSize == 1) and:[mSize == 1]) ifTrue:[^ true].
   310 		((sSize == 1) and:[mSize == 1]) ifTrue:[^ true].
   311                 "advance by one and continue"
   311 		"advance by one and continue"
   312                 mStart := mStart + 1.
   312 		mStart := mStart + 1.
   313                 sStart := sStart + 1
   313 		sStart := sStart + 1
   314             ] ifFalse:[
   314 	    ] ifFalse:[
   315                 (matchEntry == #anyString) ifTrue:[
   315 		(matchEntry == #anyString) ifTrue:[
   316                     "* alone matches anything"
   316 		    "* alone matches anything"
   317                     (mSize == 1) ifTrue:[^ true].
   317 		    (mSize == 1) ifTrue:[^ true].
   318                     "restString empty & matchString not empty -> no match"
   318 		    "restString empty & matchString not empty -> no match"
   319                     (sSize == 0) ifTrue:[^ false].
   319 		    (sSize == 0) ifTrue:[^ false].
   320 
   320 
   321                     "
   321 		    "
   322                      try to avoid some of the recursion by checking last
   322 		     try to avoid some of the recursion by checking last
   323                      character and continue with shortened strings if possible
   323 		     character and continue with shortened strings if possible
   324                     "
   324 		    "
   325                     quickCheck := false.
   325 		    quickCheck := false.
   326                     (mStop >= mStart) ifTrue:[
   326 		    (mStop >= mStart) ifTrue:[
   327                         matchLast := matchScanArray at:mStop.
   327 			matchLast := matchScanArray at:mStop.
   328                         (matchLast ~~ #anyString) ifTrue:[
   328 			(matchLast ~~ #anyString) ifTrue:[
   329                             (matchLast == #any) ifTrue:[
   329 			    (matchLast == #any) ifTrue:[
   330                                 quickCheck := true
   330 				quickCheck := true
   331                             ] ifFalse:[
   331 			    ] ifFalse:[
   332                                 matchLast == (aString at:sStop) ifTrue:[
   332 				matchLast == (aString at:sStop) ifTrue:[
   333                                     quickCheck := true
   333 				    quickCheck := true
   334                                 ] ifFalse:[
   334 				] ifFalse:[
   335                                     matchLast isString ifTrue:[
   335 				    matchLast isString ifTrue:[
   336                                         quickCheck := matchLast includes:(aString at:sStop)
   336 					quickCheck := matchLast includes:(aString at:sStop)
   337                                     ]
   337 				    ]
   338                                 ]
   338 				]
   339                             ]
   339 			    ]
   340                         ]
   340 			]
   341                     ].
   341 		    ].
   342                     quickCheck ifTrue:[
   342 		    quickCheck ifTrue:[
   343                         "
   343 			"
   344                          quickCheck ok, advance from the right
   344 			 quickCheck ok, advance from the right
   345                         "
   345 			"
   346                         mStop := mStop - 1.
   346 			mStop := mStop - 1.
   347                         sStop := sStop - 1
   347 			sStop := sStop - 1
   348                     ] ifFalse:[
   348 		    ] ifFalse:[
   349                         "/ no quick check; 
   349 			"/ no quick check;
   350                         "/ look for the next character(s)
   350 			"/ look for the next character(s)
   351                         "/ and try matching there
   351 			"/ and try matching there
   352                         "/ (to avoid recursion)
   352 			"/ (to avoid recursion)
   353 
   353 
   354                         mStart < mStop ifTrue:[
   354 			mStart < mStop ifTrue:[
   355                             nextMatchEntry := matchScanArray at:mStart+1.
   355 			    nextMatchEntry := matchScanArray at:mStart+1.
   356                             nextMatchEntry isCharacter ifTrue:[
   356 			    nextMatchEntry isCharacter ifTrue:[
   357                                 sStart <= sStop ifTrue:[
   357 				sStart <= sStop ifTrue:[
   358                                     [true] whileTrue:[
   358 				    [true] whileTrue:[
   359                                         ignoreCase ifFalse:[
   359 					ignoreCase ifFalse:[
   360                                             index := aString indexOf:nextMatchEntry startingAt:sStart
   360 					    index := aString indexOf:nextMatchEntry startingAt:sStart
   361                                         ] ifTrue:[
   361 					] ifTrue:[
   362                                             index := aString findFirst:[:c | c asLowercase = nextMatchEntry asLowercase]
   362 					    index := aString findFirst:[:c | c asLowercase = nextMatchEntry asLowercase]
   363                                                            startingAt:sStart.
   363 							   startingAt:sStart.
   364                                         ].
   364 					].
   365                                         (index == 0 or:[index > sStop]) ifTrue:[
   365 					(index == 0 or:[index > sStop]) ifTrue:[
   366                                             ^ false
   366 					    ^ false
   367                                         ].
   367 					].
   368                                         (self matchScan:matchScanArray 
   368 					(self matchScan:matchScanArray
   369                                               from:(mStart + 1) 
   369 					      from:(mStart + 1)
   370                                               to:mStop 
   370 					      to:mStop
   371                                               with:aString 
   371 					      with:aString
   372                                               from:index 
   372 					      from:index
   373                                               to:sStop 
   373 					      to:sStop
   374                                               ignoreCase:ignoreCase 
   374 					      ignoreCase:ignoreCase
   375                                         ) ifTrue:[
   375 					) ifTrue:[
   376                                             ^ true
   376 					    ^ true
   377                                         ].
   377 					].
   378                                         sStart := index + 1.
   378 					sStart := index + 1.
   379                                     ]
   379 				    ]
   380                                 ]
   380 				]
   381                             ]
   381 			    ]
   382                         ].
   382 			].
   383 
   383 
   384                         "
   384 			"
   385                          no quick check possible;
   385 			 no quick check possible;
   386                          loop over all possible substrings
   386 			 loop over all possible substrings
   387                         "
   387 			"
   388                         index := sStart.
   388 			index := sStart.
   389                         [index <= sStop] whileTrue:[
   389 			[index <= sStop] whileTrue:[
   390                             (self matchScan:matchScanArray 
   390 			    (self matchScan:matchScanArray
   391                                   from:(mStart + 1) 
   391 				  from:(mStart + 1)
   392                                   to:mStop 
   392 				  to:mStop
   393                                   with:aString 
   393 				  with:aString
   394                                   from:index 
   394 				  from:index
   395                                   to:sStop 
   395 				  to:sStop
   396                                   ignoreCase:ignoreCase 
   396 				  ignoreCase:ignoreCase
   397                             ) ifTrue:[
   397 			    ) ifTrue:[
   398                                 ^ true
   398 				^ true
   399                             ].
   399 			    ].
   400                             index := index + 1
   400 			    index := index + 1
   401                         ].
   401 			].
   402                         ^ false
   402 			^ false
   403                     ].
   403 		    ].
   404                 ] ifFalse:[
   404 		] ifFalse:[
   405                     (matchEntry isString) ifTrue:[
   405 		    (matchEntry isString) ifTrue:[
   406                         "testString empty -> no match"
   406 			"testString empty -> no match"
   407                         (sSize == 0) ifTrue:[^ false].
   407 			(sSize == 0) ifTrue:[^ false].
   408 
   408 
   409                         included := false.
   409 			included := false.
   410                         "/ checkChar := aString at:sStart.
   410 			"/ checkChar := aString at:sStart.
   411                         included := matchEntry includes:checkChar.
   411 			included := matchEntry includes:checkChar.
   412                         included ifFalse:[
   412 			included ifFalse:[
   413                             ignoreCase ifTrue:[
   413 			    ignoreCase ifTrue:[
   414                                 checkChar isUppercase ifTrue:[
   414 				checkChar isUppercase ifTrue:[
   415                                     included := matchEntry includes:checkChar asLowercase.
   415 				    included := matchEntry includes:checkChar asLowercase.
   416                                 ] ifFalse:[
   416 				] ifFalse:[
   417                                     included := matchEntry includes:checkChar asUppercase.
   417 				    included := matchEntry includes:checkChar asUppercase.
   418                                 ]
   418 				]
   419                             ].
   419 			    ].
   420                         ].
   420 			].
   421                         mStart := mStart + 1.
   421 			mStart := mStart + 1.
   422                         mSize := mSize - 1.
   422 			mSize := mSize - 1.
   423                         included ifFalse:[^ false].
   423 			included ifFalse:[^ false].
   424 
   424 
   425                         ((sSize == 1) and:[mSize == 0]) ifTrue:[^ true].
   425 			((sSize == 1) and:[mSize == 0]) ifTrue:[^ true].
   426                         "cut off 1st char and continue"
   426 			"cut off 1st char and continue"
   427                         sStart := sStart + 1
   427 			sStart := sStart + 1
   428                     ] ifFalse:[
   428 		    ] ifFalse:[
   429                         "/ must be single character
   429 			"/ must be single character
   430 
   430 
   431                         "testString empty ?"
   431 			"testString empty ?"
   432                         (sSize == 0) ifTrue:[^ false].
   432 			(sSize == 0) ifTrue:[^ false].
   433 
   433 
   434                         "first characters equal ?"
   434 			"first characters equal ?"
   435                         "/ checkChar := aString at:sStart.
   435 			"/ checkChar := aString at:sStart.
   436                         ignoreCase ifFalse:[^ false].
   436 			ignoreCase ifFalse:[^ false].
   437                         (checkChar asUppercase ~= matchEntry asUppercase) ifTrue:[^ false].
   437 			(checkChar asUppercase ~= matchEntry asUppercase) ifTrue:[^ false].
   438 
   438 
   439                         "advance and continue"
   439 			"advance and continue"
   440                         mStart := mStart + 1.
   440 			mStart := mStart + 1.
   441                         sStart := sStart + 1
   441 			sStart := sStart + 1
   442                     ]
   442 		    ]
   443                 ]
   443 		]
   444             ]
   444 	    ]
   445         ]
   445 	]
   446     ].
   446     ].
   447 
   447 
   448     "
   448     "
   449      |scanArray s|
   449      |scanArray s|
   450 
   450 
   451      scanArray := self matchScanArrayFrom:'*hello'.
   451      scanArray := self matchScanArrayFrom:'*hello'.
   452      s := 'foo bar hello world'.
   452      s := 'foo bar hello world'.
   453      CharacterArray
   453      CharacterArray
   454          matchScan:scanArray
   454 	 matchScan:scanArray
   455          from:1 
   455 	 from:1
   456          to:scanArray size
   456 	 to:scanArray size
   457          with:s
   457 	 with:s
   458          from:1
   458 	 from:1
   459          to:s size
   459 	 to:s size
   460          ignoreCase:false
   460 	 ignoreCase:false
   461     "
   461     "
   462     "
   462     "
   463      |scanArray s|
   463      |scanArray s|
   464 
   464 
   465      scanArray := self matchScanArrayFrom:'*hello*'.
   465      scanArray := self matchScanArrayFrom:'*hello*'.
   466      s := 'foo bar hello world'.
   466      s := 'foo bar hello world'.
   467      CharacterArray
   467      CharacterArray
   468          matchScan:scanArray
   468 	 matchScan:scanArray
   469          from:1 
   469 	 from:1
   470          to:scanArray size
   470 	 to:scanArray size
   471          with:s
   471 	 with:s
   472          from:1
   472 	 from:1
   473          to:s size
   473 	 to:s size
   474          ignoreCase:false
   474 	 ignoreCase:false
   475     "
   475     "
   476 
   476 
   477     "Modified: / 15.10.1998 / 13:39:25 / cg"
   477     "Modified: / 15.10.1998 / 13:39:25 / cg"
   478 !
   478 !
   479 
   479 
   480 matchScanArrayFrom:aString
   480 matchScanArrayFrom:aString
   481     "scan a pattern string and decompose it into a scanArray.
   481     "scan a pattern string and decompose it into a scanArray.
   482      This is processed faster (especially with character ranges), and
   482      This is processed faster (especially with character ranges), and
   483      can also be reused later. (if the same pattern is to be searched again)"
   483      can also be reused later. (if the same pattern is to be searched again)"
   484 
   484 
   485     |coll 
   485     |coll
   486      idx "{ Class: SmallInteger }"
   486      idx "{ Class: SmallInteger }"
   487      end c1 c2 matchSet previous escape|
   487      end c1 c2 matchSet previous escape|
   488 
   488 
   489     previous := nil.
   489     previous := nil.
   490     escape := self matchEscapeCharacter.
   490     escape := self matchEscapeCharacter.
   491 
   491 
   492     coll := OrderedCollection new.
   492     coll := OrderedCollection new.
   493     idx := 1. end := aString size.
   493     idx := 1. end := aString size.
   494     [idx <= end] whileTrue:[
   494     [idx <= end] whileTrue:[
   495         |char this|
   495 	|char this|
   496 
   496 
   497         char := aString at:idx.
   497 	char := aString at:idx.
   498         char == $* ifTrue:[
   498 	char == $* ifTrue:[
   499             previous ~~ #anyString ifTrue:[
   499 	    previous ~~ #anyString ifTrue:[
   500                 this := #anyString
   500 		this := #anyString
   501             ]
   501 	    ]
   502         ] ifFalse:[
   502 	] ifFalse:[
   503             char == $# ifTrue:[
   503 	    char == $# ifTrue:[
   504                 previous ~~ #anyString ifTrue:[
   504 		previous ~~ #anyString ifTrue:[
   505                     this := #any
   505 		    this := #any
   506                 ]
   506 		]
   507             ] ifFalse:[
   507 	    ] ifFalse:[
   508                 char == $[ ifTrue:[
   508 		char == $[ ifTrue:[
   509                     matchSet := IdentitySet new.
   509 		    matchSet := IdentitySet new.
   510                     idx := idx + 1.
   510 		    idx := idx + 1.
   511                     idx > end ifTrue:[^ nil].
   511 		    idx > end ifTrue:[^ nil].
   512                     char := aString at:idx.
   512 		    char := aString at:idx.
   513                     c1 := nil.
   513 		    c1 := nil.
   514                     [char ~~ $]] whileTrue:[
   514 		    [char ~~ $]] whileTrue:[
   515                         ((char == $-) and:[c1 notNil]) ifTrue:[
   515 			((char == $-) and:[c1 notNil]) ifTrue:[
   516                             idx := idx + 1.
   516 			    idx := idx + 1.
   517                             idx > end ifTrue:[^ nil].
   517 			    idx > end ifTrue:[^ nil].
   518                             c2 := aString at:idx.
   518 			    c2 := aString at:idx.
   519                             c1 to:c2 do:[:c | matchSet add:c].
   519 			    c1 to:c2 do:[:c | matchSet add:c].
   520                             c1 := nil.
   520 			    c1 := nil.
   521                             idx := idx + 1.
   521 			    idx := idx + 1.
   522                         ] ifFalse:[
   522 			] ifFalse:[
   523                             (char ~~ $]) ifTrue:[
   523 			    (char ~~ $]) ifTrue:[
   524                                 matchSet add:char.
   524 				matchSet add:char.
   525                                 c1 := char.
   525 				c1 := char.
   526                                 idx := idx + 1
   526 				idx := idx + 1
   527                             ]
   527 			    ]
   528                         ].
   528 			].
   529                         idx > end ifTrue:[^ nil].
   529 			idx > end ifTrue:[^ nil].
   530                         char := aString at:idx
   530 			char := aString at:idx
   531                     ].
   531 		    ].
   532                     this := matchSet asString
   532 		    this := matchSet asString
   533                 ] ifFalse:[
   533 		] ifFalse:[
   534                     char == escape ifTrue:[
   534 		    char == escape ifTrue:[
   535                         idx := idx + 1.
   535 			idx := idx + 1.
   536                         idx > end ifTrue:[
   536 			idx > end ifTrue:[
   537                             "/ mhmh - what should we do here ?
   537 			    "/ mhmh - what should we do here ?
   538                             this := char
   538 			    this := char
   539                         ] ifFalse:[
   539 			] ifFalse:[
   540                             this := aString at:idx.
   540 			    this := aString at:idx.
   541                         ]
   541 			]
   542                     ] ifFalse:[
   542 		    ] ifFalse:[
   543                         this := char
   543 			this := char
   544                     ]
   544 		    ]
   545                 ]
   545 		]
   546             ]
   546 	    ]
   547         ].
   547 	].
   548         this notNil ifTrue:[coll add:this. previous := this].
   548 	this notNil ifTrue:[coll add:this. previous := this].
   549         idx := idx + 1
   549 	idx := idx + 1
   550     ].
   550     ].
   551 
   551 
   552     ^ coll asArray
   552     ^ coll asArray
   553 
   553 
   554     "
   554     "
   555      String matchScanArrayFrom:'*ute*'  
   555      String matchScanArrayFrom:'*ute*'
   556      String matchScanArrayFrom:'**ute**'  
   556      String matchScanArrayFrom:'**ute**'
   557      String matchScanArrayFrom:'*uter'   
   557      String matchScanArrayFrom:'*uter'
   558      String matchScanArrayFrom:'\*uter'   
   558      String matchScanArrayFrom:'\*uter'
   559      String matchScanArrayFrom:'[cC]#mpute[rR]'  
   559      String matchScanArrayFrom:'[cC]#mpute[rR]'
   560      String matchScanArrayFrom:'[abcd]*'      
   560      String matchScanArrayFrom:'[abcd]*'
   561      String matchScanArrayFrom:'[a-k]*'      
   561      String matchScanArrayFrom:'[a-k]*'
   562      String matchScanArrayFrom:'*some*compl*ern*' 
   562      String matchScanArrayFrom:'*some*compl*ern*'
   563      String matchScanArrayFrom:'[a-'  
   563      String matchScanArrayFrom:'[a-'
   564      String matchScanArrayFrom:'[a-zA-Z]'  
   564      String matchScanArrayFrom:'[a-zA-Z]'
   565      String matchScanArrayFrom:'[a-z01234A-Z]'  
   565      String matchScanArrayFrom:'[a-z01234A-Z]'
   566     "
   566     "
   567 
   567 
   568     "Modified: 2.4.1997 / 16:20:29 / cg"
   568     "Modified: 2.4.1997 / 16:20:29 / cg"
   569 ! !
   569 ! !
   570 
   570 
   593 
   593 
   594     |ds|
   594     |ds|
   595 
   595 
   596     ds := WriteStream on:(self species new).
   596     ds := WriteStream on:(self species new).
   597     self do:[:eachChar |
   597     self do:[:eachChar |
   598         |repl|
   598 	|repl|
   599 
   599 
   600         repl := expandTable at:eachChar ifAbsent:nil.
   600 	repl := expandTable at:eachChar ifAbsent:nil.
   601         repl isNil ifTrue:[
   601 	repl isNil ifTrue:[
   602             ds nextPut:eachChar
   602 	    ds nextPut:eachChar
   603         ] ifFalse:[
   603 	] ifFalse:[
   604             repl size == 0 ifTrue:[
   604 	    repl size == 0 ifTrue:[
   605                 ds nextPut:repl
   605 		ds nextPut:repl
   606             ] ifFalse:[
   606 	    ] ifFalse:[
   607                 ds nextPutAll:repl
   607 		ds nextPutAll:repl
   608             ]
   608 	    ]
   609         ].
   609 	].
   610     ].
   610     ].
   611     ^ ds contents.
   611     ^ ds contents.
   612 !
   612 !
   613 
   613 
   614 formatWith:aString
   614 formatWith:aString
   653 "/    ].
   653 "/    ].
   654     ^ super at:index put:(Character value:aByte)
   654     ^ super at:index put:(Character value:aByte)
   655 
   655 
   656     "
   656     "
   657      'hello' copy at:1 put:$H asciiValue; yourself
   657      'hello' copy at:1 put:$H asciiValue; yourself
   658      'hello' copy byteAt:1 put:72; yourself 
   658      'hello' copy byteAt:1 put:72; yourself
   659      'hello' copy byteAt:1 put:0; yourself 
   659      'hello' copy byteAt:1 put:0; yourself
   660     "
   660     "
   661 
   661 
   662     "Modified: 6.5.1996 / 10:35:26 / cg"
   662     "Modified: 6.5.1996 / 10:35:26 / cg"
   663 !
   663 !
   664 
   664 
   668      This is an ST/V compatibility method."
   668      This is an ST/V compatibility method."
   669 
   669 
   670     ^ self copyReplaceAll:oldChar with:newChar
   670     ^ self copyReplaceAll:oldChar with:newChar
   671 
   671 
   672     "
   672     "
   673      '12345678901234567890' replChar:$0 with:$* 
   673      '12345678901234567890' replChar:$0 with:$*
   674     "
   674     "
   675 
   675 
   676     "Modified: / 18.7.1998 / 22:52:57 / cg"
   676     "Modified: / 18.7.1998 / 22:52:57 / cg"
   677 !
   677 !
   678 
   678 
   686     tmpStream := WriteStream on:(self class new).
   686     tmpStream := WriteStream on:(self class new).
   687     self do:[:element |
   687     self do:[:element |
   688 	element = oldChar ifTrue:[
   688 	element = oldChar ifTrue:[
   689 	    tmpStream nextPutAll:newString
   689 	    tmpStream nextPutAll:newString
   690 	] ifFalse:[
   690 	] ifFalse:[
   691 	    tmpStream nextPut:element 
   691 	    tmpStream nextPut:element
   692 	].
   692 	].
   693     ].
   693     ].
   694     ^ tmpStream contents
   694     ^ tmpStream contents
   695 
   695 
   696    "
   696    "
   697      '12345678901234567890' replChar:$0 withString:'foo' 
   697      '12345678901234567890' replChar:$0 withString:'foo'
   698      'a string with spaces' replChar:$  withString:' foo '  
   698      'a string with spaces' replChar:$  withString:' foo '
   699     "
   699     "
   700 !
   700 !
   701 
   701 
   702 replString:subString withString:newString
   702 replString:subString withString:newString
   703     "return a copy of the receiver, with all sequences of subString replaced
   703     "return a copy of the receiver, with all sequences of subString replaced
   704      by newString (i.e. slice in the newString in place of the oldString)."
   704      by newString (i.e. slice in the newString in place of the oldString)."
   705 
   705 
   706     ^ self copyReplaceString:subString withString:newString
   706     ^ self copyReplaceString:subString withString:newString
   707 
   707 
   708    "
   708    "
   709      '12345678901234567890' replString:'123' withString:'OneTwoThree' 
   709      '12345678901234567890' replString:'123' withString:'OneTwoThree'
   710      '12345678901234567890' replString:'123' withString:'*' 
   710      '12345678901234567890' replString:'123' withString:'*'
   711      '12345678901234567890' replString:'234' withString:'foo' 
   711      '12345678901234567890' replString:'234' withString:'foo'
   712 
   712 
   713      ('a string with spaces' replChar:$  withString:' foo ')
   713      ('a string with spaces' replChar:$  withString:' foo ')
   714         replString:'foo' withString:'bar'
   714 	replString:'foo' withString:'bar'
   715     "
   715     "
   716 
   716 
   717     "Modified: / 12-05-2004 / 12:00:27 / cg"
   717     "Modified: / 12-05-2004 / 12:00:27 / cg"
   718 !
   718 !
   719 
   719 
   723      This is an ST/V compatibility method."
   723      This is an ST/V compatibility method."
   724 
   724 
   725     ^ self withoutSpaces
   725     ^ self withoutSpaces
   726 
   726 
   727     "
   727     "
   728      '    spaces at beginning' trimBlanks     
   728      '    spaces at beginning' trimBlanks
   729      'spaces at end    ' trimBlanks           
   729      'spaces at end    ' trimBlanks
   730      '    spaces at beginning and end     ' trimBlanks    
   730      '    spaces at beginning and end     ' trimBlanks
   731      'no spaces' trimBlanks              
   731      'no spaces' trimBlanks
   732     "
   732     "
   733 ! !
   733 ! !
   734 
   734 
   735 !CharacterArray methodsFor:'Compatibility-Squeak'!
   735 !CharacterArray methodsFor:'Compatibility-Squeak'!
   736 
   736 
   738     "Many allowed forms, see Date.readFrom:"
   738     "Many allowed forms, see Date.readFrom:"
   739 
   739 
   740     ^ Date readFrom: (ReadStream on: self)
   740     ^ Date readFrom: (ReadStream on: self)
   741 
   741 
   742     "
   742     "
   743      '30 Apr 1999' asDate dayName capitalized    
   743      '30 Apr 1999' asDate dayName capitalized
   744     "
   744     "
   745 !
   745 !
   746 
   746 
   747 capitalized
   747 capitalized
   748     ^ self asUppercaseFirst
   748     ^ self asUppercaseFirst
   752     "
   752     "
   753 !
   753 !
   754 
   754 
   755 displayProgressAt:aPointOrNil from:start to:stop during:aBlock
   755 displayProgressAt:aPointOrNil from:start to:stop during:aBlock
   756      ProgressIndicator
   756      ProgressIndicator
   757         displayProgress:self
   757 	displayProgress:self
   758         at:aPointOrNil
   758 	at:aPointOrNil
   759         from:start
   759 	from:start
   760         to:stop
   760 	to:stop
   761         during:aBlock.
   761 	during:aBlock.
   762 
   762 
   763     "
   763     "
   764      'dobedobedoobedoo'
   764      'dobedobedoobedoo'
   765         displayProgressAt:(Screen current center)
   765 	displayProgressAt:(Screen current center)
   766         from:0 to:100
   766 	from:0 to:100
   767         during:[:val |
   767 	during:[:val |
   768                 0 to:100 do:[:i |
   768 		0 to:100 do:[:i |
   769                     val value:i.
   769 		    val value:i.
   770                     Delay waitForSeconds:0.05.
   770 		    Delay waitForSeconds:0.05.
   771                 ]
   771 		]
   772                ]
   772 	       ]
   773     "
   773     "
   774 !
   774 !
   775 
   775 
   776 endsWithDigit
   776 endsWithDigit
   777     "Answer whether the receiver's final character represents a digit.  3/11/96 sw"
   777     "Answer whether the receiver's final character represents a digit.  3/11/96 sw"
   783     "cg: I am not sure, if this is really the squeak semantics (w.r.t. empty fields)"
   783     "cg: I am not sure, if this is really the squeak semantics (w.r.t. empty fields)"
   784 
   784 
   785     ^ self asCollectionOfSubstringsSeparatedByAny:delimiters
   785     ^ self asCollectionOfSubstringsSeparatedByAny:delimiters
   786 
   786 
   787     "
   787     "
   788      'a|b#c||e' findTokens:#($# $|) 
   788      'a|b#c||e' findTokens:#($# $|)
   789     "
   789     "
   790 !
   790 !
   791 
   791 
   792 includesSubString:aString
   792 includesSubString:aString
   793     "return true, if a substring is contained in the receiver.
   793     "return true, if a substring is contained in the receiver.
   794      The compare is case sensitive."
   794      The compare is case sensitive."
   795 
   795 
   796     ^ self includesString:aString
   796     ^ self includesString:aString
   797 
   797 
   798     "
   798     "
   799      'hello world' includesSubString:'Hel'  
   799      'hello world' includesSubString:'Hel'
   800      'hello world' includesSubString:'hel'  
   800      'hello world' includesSubString:'hel'
   801      'hello world' includesSubString:'llo'  
   801      'hello world' includesSubString:'llo'
   802     "
   802     "
   803 
   803 
   804 
   804 
   805 
   805 
   806 !
   806 !
   810      The argument, caseSensitive controls if case is ignored in the compare."
   810      The argument, caseSensitive controls if case is ignored in the compare."
   811 
   811 
   812     "/ for now,  a q&d hack ...
   812     "/ for now,  a q&d hack ...
   813 
   813 
   814     caseSensitive ifFalse:[
   814     caseSensitive ifFalse:[
   815         ^ self asLowercase includesString:aString asLowercase
   815 	^ self asLowercase includesString:aString asLowercase
   816     ].
   816     ].
   817     ^ self includesString:aString
   817     ^ self includesString:aString
   818 
   818 
   819     "
   819     "
   820      'hello world' includesSubstring:'Hel' caseSensitive:true  
   820      'hello world' includesSubstring:'Hel' caseSensitive:true
   821      'hello world' includesSubstring:'Hel' caseSensitive:false 
   821      'hello world' includesSubstring:'Hel' caseSensitive:false
   822     "
   822     "
   823 
   823 
   824 
   824 
   825 
   825 
   826 !
   826 !
   840     ^ self lastIndexOfSeparator
   840     ^ self lastIndexOfSeparator
   841 !
   841 !
   842 
   842 
   843 padded:leftOrRight to:paddedSize with:padCharacter
   843 padded:leftOrRight to:paddedSize with:padCharacter
   844     leftOrRight == #left ifTrue:[
   844     leftOrRight == #left ifTrue:[
   845         ^ self leftPaddedTo:paddedSize with:padCharacter
   845 	^ self leftPaddedTo:paddedSize with:padCharacter
   846     ].
   846     ].
   847     ^ self paddedTo:paddedSize with:padCharacter
   847     ^ self paddedTo:paddedSize with:padCharacter
   848 
   848 
   849     "
   849     "
   850      'hello' padded:#right to:10 with:$.  
   850      'hello' padded:#right to:10 with:$.
   851      'hello' padded:#left to:10 with:$.   
   851      'hello' padded:#left to:10 with:$.
   852     "
   852     "
   853 !
   853 !
   854 
   854 
   855 skipDelimiters:delimiters startingAt:start 
   855 skipDelimiters:delimiters startingAt:start
   856     "Answer the index of the character within the receiver, starting at start, 
   856     "Answer the index of the character within the receiver, starting at start,
   857      that does NOT match one of the delimiters. 
   857      that does NOT match one of the delimiters.
   858      If the receiver does not contain any of the delimiters, answer size + 1.  
   858      If the receiver does not contain any of the delimiters, answer size + 1.
   859      Assumes the delimiters to be a non-empty string."
   859      Assumes the delimiters to be a non-empty string."
   860     
   860 
   861     start to:self size do:[:i | 
   861     start to:self size do:[:i |
   862         delimiters detect:[:delim | delim = (self at:i) ] ifNone:[ ^ i ]
   862 	delimiters detect:[:delim | delim = (self at:i) ] ifNone:[ ^ i ]
   863     ].
   863     ].
   864     ^ self size + 1
   864     ^ self size + 1
   865 
   865 
   866     "
   866     "
   867      '123***7890' skipDelimiters:'*' startingAt:4 
   867      '123***7890' skipDelimiters:'*' startingAt:4
   868      '123***7890' skipDelimiters:'*' startingAt:3 
   868      '123***7890' skipDelimiters:'*' startingAt:3
   869      '123***7890' skipDelimiters:'*' startingAt:10 
   869      '123***7890' skipDelimiters:'*' startingAt:10
   870      '123*******' skipDelimiters:'*' startingAt:10  
   870      '123*******' skipDelimiters:'*' startingAt:10
   871     "
   871     "
   872 !
   872 !
   873 
   873 
   874 substrings
   874 substrings
   875     ^ self asCollectionOfWords
   875     ^ self asCollectionOfWords
   884 
   884 
   885     self size <= smallSize ifTrue:[^ self].
   885     self size <= smallSize ifTrue:[^ self].
   886     ^ self copyFrom: 1 to: smallSize
   886     ^ self copyFrom: 1 to: smallSize
   887 
   887 
   888     "
   888     "
   889      'hello world' truncateTo:5 
   889      'hello world' truncateTo:5
   890      'hello' truncateTo:10      
   890      'hello' truncateTo:10
   891 
   891 
   892      'hello world' copyTo:5       
   892      'hello world' copyTo:5
   893      'hello' copyTo:10
   893      'hello' copyTo:10
   894     "
   894     "
   895 !
   895 !
   896 
   896 
   897 withBlanksTrimmed
   897 withBlanksTrimmed
   898     "Return a copy of the receiver from which leading and trailing blanks have been trimmed."
   898     "Return a copy of the receiver from which leading and trailing blanks have been trimmed."
   899 
   899 
   900     ^ self withoutSpaces
   900     ^ self withoutSpaces
   901 
   901 
   902     "
   902     "
   903      '  hello    world    ' withBlanksTrimmed  
   903      '  hello    world    ' withBlanksTrimmed
   904     "
   904     "
   905 
   905 
   906 
   906 
   907 
   907 
   908 !
   908 !
   914 
   914 
   915     aNumber isNumber not | (aNumber < 1) ifTrue: [self error: 'too narrow'].
   915     aNumber isNumber not | (aNumber < 1) ifTrue: [self error: 'too narrow'].
   916     listOfLines _ OrderedCollection new.
   916     listOfLines _ OrderedCollection new.
   917     currentLast _ 0.
   917     currentLast _ 0.
   918     [currentLast < self size] whileTrue:
   918     [currentLast < self size] whileTrue:
   919             [currentStart _ currentLast + 1.
   919 	    [currentStart _ currentLast + 1.
   920             putativeLast _ (currentStart + aNumber - 1) min: self size.
   920 	    putativeLast _ (currentStart + aNumber - 1) min: self size.
   921             putativeLine _ self copyFrom: currentStart to: putativeLast.
   921 	    putativeLine _ self copyFrom: currentStart to: putativeLast.
   922             (crPosition _ putativeLine indexOf: Character cr) > 0 ifTrue:
   922 	    (crPosition _ putativeLine indexOf: Character cr) > 0 ifTrue:
   923                     [putativeLast _ currentStart + crPosition - 1.
   923 		    [putativeLast _ currentStart + crPosition - 1.
   924                     putativeLine _ self copyFrom: currentStart to: putativeLast].
   924 		    putativeLine _ self copyFrom: currentStart to: putativeLast].
   925             currentLast _ putativeLast == self size
   925 	    currentLast _ putativeLast == self size
   926                     ifTrue:
   926 		    ifTrue:
   927                             [putativeLast]
   927 			    [putativeLast]
   928                     ifFalse:
   928 		    ifFalse:
   929                             [currentStart + putativeLine lastSpacePosition - 1].
   929 			    [currentStart + putativeLine lastSpacePosition - 1].
   930             currentLast <= currentStart ifTrue:
   930 	    currentLast <= currentStart ifTrue:
   931                     ["line has NO spaces; baleout!!"
   931 		    ["line has NO spaces; baleout!!"
   932                     currentLast _ putativeLast].
   932 		    currentLast _ putativeLast].
   933             listOfLines add: (self copyFrom: currentStart to: currentLast) withBlanksTrimmed].
   933 	    listOfLines add: (self copyFrom: currentStart to: currentLast) withBlanksTrimmed].
   934 
   934 
   935     listOfLines size > 0 ifFalse: [^ ''].
   935     listOfLines size > 0 ifFalse: [^ ''].
   936     resultString _ listOfLines first.
   936     resultString _ listOfLines first.
   937     2 to: listOfLines size do:
   937     2 to: listOfLines size do:
   938             [:i | resultString _ resultString, Character cr asString, (listOfLines at: i)].
   938 	    [:i | resultString _ resultString, Character cr asString, (listOfLines at: i)].
   939     ^ resultString
   939     ^ resultString
   940 
   940 
   941     "
   941     "
   942      #(5 7 20) collect:
   942      #(5 7 20) collect:
   943         [:i | 'Fred the bear went down to the brook to read his book in silence' withNoLineLongerThan: i]
   943 	[:i | 'Fred the bear went down to the brook to read his book in silence' withNoLineLongerThan: i]
   944     "
   944     "
   945 
   945 
   946 
   946 
   947 
   947 
   948 ! !
   948 ! !
  1020 bindWith:str1 with:str2 with:str3 with:str4 with:str5 with:str6
  1020 bindWith:str1 with:str2 with:str3 with:str4 with:str5 with:str6
  1021     "return a copy of the receiver, where a '%1' .. '%6' escapes
  1021     "return a copy of the receiver, where a '%1' .. '%6' escapes
  1022      are replaced by str1 .. str5 respectively.
  1022      are replaced by str1 .. str5 respectively.
  1023      This has been added for VisualAge compatibility."
  1023      This has been added for VisualAge compatibility."
  1024 
  1024 
  1025     ^ self expandPlaceholdersWith:(Array with:str1 with:str2 
  1025     ^ self expandPlaceholdersWith:(Array with:str1 with:str2
  1026                                          with:str3 with:str4 
  1026 					 with:str3 with:str4
  1027                                          with:str5 with:str6)
  1027 					 with:str5 with:str6)
  1028 
  1028 
  1029 !
  1029 !
  1030 
  1030 
  1031 bindWithArguments:anArrayOfStrings
  1031 bindWithArguments:anArrayOfStrings
  1032     "return a copy of the receiver, where a '%i' escape
  1032     "return a copy of the receiver, where a '%i' escape
  1151 
  1151 
  1152     in := self readStream.
  1152     in := self readStream.
  1153     out := WriteStream on:(String uninitializedNew:self size).
  1153     out := WriteStream on:(String uninitializedNew:self size).
  1154 
  1154 
  1155     [in atEnd] whileFalse:[
  1155     [in atEnd] whileFalse:[
  1156         c := in next.
  1156 	c := in next.
  1157         c == $% ifTrue:[
  1157 	c == $% ifTrue:[
  1158             c := in next.
  1158 	    c := in next.
  1159             out nextPut:c
  1159 	    out nextPut:c
  1160         ] ifFalse:[
  1160 	] ifFalse:[
  1161             c == $< ifTrue:[
  1161 	    c == $< ifTrue:[
  1162                 [in peek == $<] whileTrue:[
  1162 		[in peek == $<] whileTrue:[
  1163                     out nextPut:$<.
  1163 		    out nextPut:$<.
  1164                     in next.
  1164 		    in next.
  1165                 ].
  1165 		].
  1166                 in peek == $n ifTrue:[
  1166 		in peek == $n ifTrue:[
  1167                     out nextPut:Character cr.
  1167 		    out nextPut:Character cr.
  1168                     in next
  1168 		    in next
  1169                 ] ifFalse:[in peek == $t ifTrue:[
  1169 		] ifFalse:[in peek == $t ifTrue:[
  1170                     out nextPut:Character tab.
  1170 		    out nextPut:Character tab.
  1171                     in next
  1171 		    in next
  1172                 ] ifFalse:[
  1172 		] ifFalse:[
  1173                     in peek isDigit ifFalse:[
  1173 		    in peek isDigit ifFalse:[
  1174                         nr := 1
  1174 			nr := 1
  1175                     ] ifTrue:[
  1175 		    ] ifTrue:[
  1176                         "/ start an argument expansion ...
  1176 			"/ start an argument expansion ...
  1177                         nr := Integer readFrom:in onError:nil.
  1177 			nr := Integer readFrom:in onError:nil.
  1178                         nr isNil ifTrue:[
  1178 			nr isNil ifTrue:[
  1179                             "/ what does VW do here ?
  1179 			    "/ what does VW do here ?
  1180                             self error:'invalid format' mayProceed:true.
  1180 			    self error:'invalid format' mayProceed:true.
  1181                             ^ self
  1181 			    ^ self
  1182                         ].
  1182 			].
  1183                         (nr between:1 and:argArray size) ifFalse:[
  1183 			(nr between:1 and:argArray size) ifFalse:[
  1184                             "/ what does VW do here ?
  1184 			    "/ what does VW do here ?
  1185                             self error:'invalid format - bad argNr' mayProceed:true.
  1185 			    self error:'invalid format - bad argNr' mayProceed:true.
  1186                             ^ self
  1186 			    ^ self
  1187                         ].
  1187 			].
  1188                     ].
  1188 		    ].
  1189                     arg := argArray at:nr.
  1189 		    arg := argArray at:nr.
  1190 
  1190 
  1191                     fmt := in next.
  1191 		    fmt := in next.
  1192                     (fmt == $p) ifTrue:[
  1192 		    (fmt == $p) ifTrue:[
  1193                         "/ expand with args printString
  1193 			"/ expand with args printString
  1194                         out nextPutAll:arg printString.
  1194 			out nextPutAll:arg printString.
  1195                     ] ifFalse:[ (fmt == $s) ifTrue:[
  1195 		    ] ifFalse:[ (fmt == $s) ifTrue:[
  1196                         "/ expand with arg itself
  1196 			"/ expand with arg itself
  1197                         arg isText ifTrue:[
  1197 			arg isText ifTrue:[
  1198                             out := (WriteStream on:(Text new)) nextPutAll:(out contents); yourself.
  1198 			    out := (WriteStream on:(Text new)) nextPutAll:(out contents); yourself.
  1199                             out nextPutAll:arg asText.
  1199 			    out nextPutAll:arg asText.
  1200                         ] ifFalse:[
  1200 			] ifFalse:[
  1201                             out nextPutAll:arg asString string.
  1201 			    out nextPutAll:arg asString string.
  1202                         ]
  1202 			]
  1203                     ] ifFalse:[ (fmt == $?) ifTrue:[
  1203 		    ] ifFalse:[ (fmt == $?) ifTrue:[
  1204                         s1 := in upTo:$:.
  1204 			s1 := in upTo:$:.
  1205                         s2 := in nextUpTo:$>.
  1205 			s2 := in nextUpTo:$>.
  1206                         arg ifTrue:[
  1206 			arg ifTrue:[
  1207                             out nextPutAll:s1
  1207 			    out nextPutAll:s1
  1208                         ] ifFalse:[
  1208 			] ifFalse:[
  1209                             out nextPutAll:s2
  1209 			    out nextPutAll:s2
  1210                         ].
  1210 			].
  1211                     ] ifFalse:[
  1211 		    ] ifFalse:[
  1212                         "/ what does VW do here ?
  1212 			"/ what does VW do here ?
  1213                         self error:'invalid format' mayProceed:true.
  1213 			self error:'invalid format' mayProceed:true.
  1214                         ^ self
  1214 			^ self
  1215                     ]]].
  1215 		    ]]].
  1216                 ]].
  1216 		]].
  1217                 c := in next.
  1217 		c := in next.
  1218                 c ~~ $> ifTrue:[
  1218 		c ~~ $> ifTrue:[
  1219                     "/ what does VW do here ?
  1219 		    "/ what does VW do here ?
  1220                     self error:'invalid format' mayProceed:true.
  1220 		    self error:'invalid format' mayProceed:true.
  1221                     ^ self
  1221 		    ^ self
  1222                 ]
  1222 		]
  1223             ] ifFalse:[
  1223 	    ] ifFalse:[
  1224                 out nextPut:c
  1224 		out nextPut:c
  1225             ]
  1225 	    ]
  1226         ].
  1226 	].
  1227     ].
  1227     ].
  1228     ^ out contents
  1228     ^ out contents
  1229 
  1229 
  1230     "
  1230     "
  1231      'hello <1s> how are you' expandMacrosWith:(OperatingSystem getLoginName) 
  1231      'hello <1s> how are you' expandMacrosWith:(OperatingSystem getLoginName)
  1232      'one plus one is <1p>' expandMacrosWith:2    
  1232      'one plus one is <1p>' expandMacrosWith:2
  1233     "
  1233     "
  1234 
  1234 
  1235     "Modified: / 18.6.1998 / 16:04:46 / cg"
  1235     "Modified: / 18.6.1998 / 16:04:46 / cg"
  1236 !
  1236 !
  1237 
  1237 
  1241 ! !
  1241 ! !
  1242 
  1242 
  1243 !CharacterArray methodsFor:'character searching'!
  1243 !CharacterArray methodsFor:'character searching'!
  1244 
  1244 
  1245 includesMatchCharacters
  1245 includesMatchCharacters
  1246     "return true if the receiver includes any meta characters (i.e. $* or $#) 
  1246     "return true if the receiver includes any meta characters (i.e. $* or $#)
  1247      for match operations; false if not.
  1247      for match operations; false if not.
  1248      Here, do not care for $\ escapes"
  1248      Here, do not care for $\ escapes"
  1249 
  1249 
  1250     ^ self includesAny:'*#['
  1250     ^ self includesAny:'*#['
  1251 
  1251 
  1252     "
  1252     "
  1253      '*foo' includesMatchCharacters   
  1253      '*foo' includesMatchCharacters
  1254      '\*foo' includesMatchCharacters  
  1254      '\*foo' includesMatchCharacters
  1255      '\*foo' includesUnescapedMatchCharacters  
  1255      '\*foo' includesUnescapedMatchCharacters
  1256      '*foo' includesMatchCharacters   
  1256      '*foo' includesMatchCharacters
  1257      '\\*foo' includesMatchCharacters
  1257      '\\*foo' includesMatchCharacters
  1258      'foo*' includesMatchCharacters
  1258      'foo*' includesMatchCharacters
  1259      'foo\*' includesMatchCharacters
  1259      'foo\*' includesMatchCharacters
  1260      'foo\' includesMatchCharacters
  1260      'foo\' includesMatchCharacters
  1261     "
  1261     "
  1267     "return true, if the receiver contains any whitespace characters"
  1267     "return true, if the receiver contains any whitespace characters"
  1268 
  1268 
  1269     ^ (self indexOfSeparator ~~ 0)
  1269     ^ (self indexOfSeparator ~~ 0)
  1270 
  1270 
  1271     "
  1271     "
  1272      'hello world' includesSeparator 
  1272      'hello world' includesSeparator
  1273      'helloworld' includesSeparator  
  1273      'helloworld' includesSeparator
  1274     "
  1274     "
  1275 !
  1275 !
  1276 
  1276 
  1277 includesUnescapedMatchCharacters
  1277 includesUnescapedMatchCharacters
  1278     "return true if the receiver really includes any meta characters (i.e. $* or $#) 
  1278     "return true if the receiver really includes any meta characters (i.e. $* or $#)
  1279      for match operations; false if not.
  1279      for match operations; false if not.
  1280      Here, care for $\ escapes"
  1280      Here, care for $\ escapes"
  1281 
  1281 
  1282     |idx sz specialChars escape|
  1282     |idx sz specialChars escape|
  1283 
  1283 
  1284     idx := 1.
  1284     idx := 1.
  1285     sz := self size.
  1285     sz := self size.
  1286     specialChars := '*#[\'.
  1286     specialChars := '*#[\'.
  1287     (escape := self class matchEscapeCharacter) ~~ $\ ifTrue:[
  1287     (escape := self class matchEscapeCharacter) ~~ $\ ifTrue:[
  1288         specialChars := specialChars copy.
  1288 	specialChars := specialChars copy.
  1289         specialChars at:specialChars size put:escape
  1289 	specialChars at:specialChars size put:escape
  1290     ].
  1290     ].
  1291 
  1291 
  1292     [true] whileTrue:[
  1292     [true] whileTrue:[
  1293         idx := self indexOfAny:specialChars startingAt:idx.
  1293 	idx := self indexOfAny:specialChars startingAt:idx.
  1294         idx == 0 ifTrue:[^ false].
  1294 	idx == 0 ifTrue:[^ false].
  1295         (self at:idx) == escape ifFalse:[^ true].
  1295 	(self at:idx) == escape ifFalse:[^ true].
  1296         idx := idx + 2.
  1296 	idx := idx + 2.
  1297         idx > sz ifTrue:[^ false].
  1297 	idx > sz ifTrue:[^ false].
  1298     ].    
  1298     ].
  1299 
  1299 
  1300     "
  1300     "
  1301      '*foo' includesUnescapedMatchCharacters    
  1301      '*foo' includesUnescapedMatchCharacters
  1302      '\*foo' includesUnescapedMatchCharacters 
  1302      '\*foo' includesUnescapedMatchCharacters
  1303      '\\foo' includesUnescapedMatchCharacters  
  1303      '\\foo' includesUnescapedMatchCharacters
  1304      '\\\$foo' includesUnescapedMatchCharacters  
  1304      '\\\$foo' includesUnescapedMatchCharacters
  1305      '*foo' includesUnescapedMatchCharacters
  1305      '*foo' includesUnescapedMatchCharacters
  1306      '\\*foo' includesUnescapedMatchCharacters
  1306      '\\*foo' includesUnescapedMatchCharacters
  1307      'foo*' includesUnescapedMatchCharacters
  1307      'foo*' includesUnescapedMatchCharacters
  1308      'foo\*' includesUnescapedMatchCharacters
  1308      'foo\*' includesUnescapedMatchCharacters
  1309      'foo\' includesUnescapedMatchCharacters
  1309      'foo\' includesUnescapedMatchCharacters
  1324 
  1324 
  1325     start := startIndex.
  1325     start := startIndex.
  1326     mySize := self size.
  1326     mySize := self size.
  1327 
  1327 
  1328     start to:mySize do:[:index |
  1328     start to:mySize do:[:index |
  1329         (self at:index) isControlCharacter ifTrue:[^ index]
  1329 	(self at:index) isControlCharacter ifTrue:[^ index]
  1330     ].
  1330     ].
  1331     ^ 0
  1331     ^ 0
  1332 
  1332 
  1333     "
  1333     "
  1334      'hello world' asTwoByteString            indexOfControlCharacterStartingAt:1
  1334      'hello world' asTwoByteString            indexOfControlCharacterStartingAt:1
  1343      return 0 if no non-separator was found"
  1343      return 0 if no non-separator was found"
  1344 
  1344 
  1345     ^ self indexOfNonSeparatorStartingAt:1.
  1345     ^ self indexOfNonSeparatorStartingAt:1.
  1346 
  1346 
  1347     "
  1347     "
  1348      '    hello world' indexOfNonSeparator 
  1348      '    hello world' indexOfNonSeparator
  1349      '    ' indexOfNonSeparator            
  1349      '    ' indexOfNonSeparator
  1350      'a   ' indexOfNonSeparator           
  1350      'a   ' indexOfNonSeparator
  1351      'abc' indexOfNonSeparator           
  1351      'abc' indexOfNonSeparator
  1352      ' ' indexOfNonSeparator           
  1352      ' ' indexOfNonSeparator
  1353      '' indexOfNonSeparator           
  1353      '' indexOfNonSeparator
  1354     "
  1354     "
  1355 !
  1355 !
  1356 
  1356 
  1357 indexOfNonSeparatorStartingAt:startIndex
  1357 indexOfNonSeparatorStartingAt:startIndex
  1358     "return the index of the next non-whitespace character,
  1358     "return the index of the next non-whitespace character,
  1364 
  1364 
  1365     start := startIndex.
  1365     start := startIndex.
  1366     mySize := self size.
  1366     mySize := self size.
  1367 
  1367 
  1368     start to:mySize do:[:index |
  1368     start to:mySize do:[:index |
  1369         (self at:index) isSeparator ifFalse:[^ index]
  1369 	(self at:index) isSeparator ifFalse:[^ index]
  1370     ].
  1370     ].
  1371     ^ 0
  1371     ^ 0
  1372 
  1372 
  1373     "
  1373     "
  1374      '    hello world' indexOfNonSeparatorStartingAt:1 
  1374      '    hello world' indexOfNonSeparatorStartingAt:1
  1375      '    ' indexOfNonSeparatorStartingAt:1            
  1375      '    ' indexOfNonSeparatorStartingAt:1
  1376      'a   ' indexOfNonSeparatorStartingAt:2            
  1376      'a   ' indexOfNonSeparatorStartingAt:2
  1377     "
  1377     "
  1378 
  1378 
  1379     "
  1379     "
  1380      |s index1 index2|
  1380      |s index1 index2|
  1381      s := '   foo    bar      baz'.
  1381      s := '   foo    bar      baz'.
  1391      return 0 if no separator was found"
  1391      return 0 if no separator was found"
  1392 
  1392 
  1393     ^ self indexOfSeparatorStartingAt:1
  1393     ^ self indexOfSeparatorStartingAt:1
  1394 
  1394 
  1395     "
  1395     "
  1396      'hello world' indexOfSeparator 
  1396      'hello world' indexOfSeparator
  1397      'helloworld' indexOfSeparator  
  1397      'helloworld' indexOfSeparator
  1398      'hello   ' indexOfSeparator    
  1398      'hello   ' indexOfSeparator
  1399      '   hello' indexOfSeparator    
  1399      '   hello' indexOfSeparator
  1400     "
  1400     "
  1401 !
  1401 !
  1402 
  1402 
  1403 indexOfSeparatorStartingAt:startIndex
  1403 indexOfSeparatorStartingAt:startIndex
  1404     "return the index of the next whitespace character,
  1404     "return the index of the next whitespace character,
  1410 
  1410 
  1411     start := startIndex.
  1411     start := startIndex.
  1412     mySize := self size.
  1412     mySize := self size.
  1413 
  1413 
  1414     start to:mySize do:[:index |
  1414     start to:mySize do:[:index |
  1415         (self at:index) isSeparator ifTrue:[^ index]
  1415 	(self at:index) isSeparator ifTrue:[^ index]
  1416     ].
  1416     ].
  1417     ^ 0
  1417     ^ 0
  1418 
  1418 
  1419     "
  1419     "
  1420      'hello world' indexOfSeparatorStartingAt:3   
  1420      'hello world' indexOfSeparatorStartingAt:3
  1421      ' hello world' indexOfSeparatorStartingAt:3  
  1421      ' hello world' indexOfSeparatorStartingAt:3
  1422      'hello world ' indexOfSeparatorStartingAt:3  
  1422      'hello world ' indexOfSeparatorStartingAt:3
  1423      'hello world ' indexOfSeparatorStartingAt:6  
  1423      'hello world ' indexOfSeparatorStartingAt:6
  1424      'hello world ' indexOfSeparatorStartingAt:7  
  1424      'hello world ' indexOfSeparatorStartingAt:7
  1425      'helloworld ' indexOfSeparatorStartingAt:7   
  1425      'helloworld ' indexOfSeparatorStartingAt:7
  1426      'helloworld' indexOfSeparatorStartingAt:7   
  1426      'helloworld' indexOfSeparatorStartingAt:7
  1427     "
  1427     "
  1428 !
  1428 !
  1429 
  1429 
  1430 lastIndexOfSeparator
  1430 lastIndexOfSeparator
  1431     "return the last index of the whitespace character.
  1431     "return the last index of the whitespace character.
  1433      Returns 0 if no separator is found."
  1433      Returns 0 if no separator is found."
  1434 
  1434 
  1435     ^ self lastIndexOfSeparatorStartingAt:(self size)
  1435     ^ self lastIndexOfSeparatorStartingAt:(self size)
  1436 
  1436 
  1437     "
  1437     "
  1438      'hello world' lastIndexOfSeparator  
  1438      'hello world' lastIndexOfSeparator
  1439      'helloworld' lastIndexOfSeparator      
  1439      'helloworld' lastIndexOfSeparator
  1440      'hel lo wor ld' lastIndexOfSeparator   
  1440      'hel lo wor ld' lastIndexOfSeparator
  1441      'hel   ' lastIndexOfSeparator 6  
  1441      'hel   ' lastIndexOfSeparator 6
  1442     "
  1442     "
  1443 !
  1443 !
  1444 
  1444 
  1445 lastIndexOfSeparatorStartingAt:startIndex
  1445 lastIndexOfSeparatorStartingAt:startIndex
  1446     "return the index of the previous whitespace character,
  1446     "return the index of the previous whitespace character,
  1450     |start  "{ Class: SmallInteger }"|
  1450     |start  "{ Class: SmallInteger }"|
  1451 
  1451 
  1452     start := startIndex.
  1452     start := startIndex.
  1453 
  1453 
  1454     start to:1 by:-1 do:[:index |
  1454     start to:1 by:-1 do:[:index |
  1455         (self at:index) isSeparator ifTrue:[^ index]
  1455 	(self at:index) isSeparator ifTrue:[^ index]
  1456     ].
  1456     ].
  1457     ^ 0
  1457     ^ 0
  1458 
  1458 
  1459     "
  1459     "
  1460      'hello world' lastIndexOfSeparatorStartingAt:3
  1460      'hello world' lastIndexOfSeparatorStartingAt:3
  1461      'hello world' lastIndexOfSeparatorStartingAt:7
  1461      'hello world' lastIndexOfSeparatorStartingAt:7
  1462      'helloworld' lastIndexOfSeparatorStartingAt:7 
  1462      'helloworld' lastIndexOfSeparatorStartingAt:7
  1463      ' helloworld' lastIndexOfSeparatorStartingAt:7 
  1463      ' helloworld' lastIndexOfSeparatorStartingAt:7
  1464     "
  1464     "
  1465 ! !
  1465 ! !
  1466 
  1466 
  1467 !CharacterArray methodsFor:'comparing'!
  1467 !CharacterArray methodsFor:'comparing'!
  1468 
  1468 
  1469 < aString
  1469 < aString
  1470     "Compare the receiver with the argument and return true if the
  1470     "Compare the receiver with the argument and return true if the
  1471      receiver is greater than the argument. Otherwise return false.
  1471      receiver is greater than the argument. Otherwise return false.
  1472      This comparison is based on the elements ascii code - 
  1472      This comparison is based on the elements ascii code -
  1473      i.e. upper/lowercase & upper/lowercase & national characters are NOT treated specially."
  1473      i.e. upper/lowercase & upper/lowercase & national characters are NOT treated specially."
  1474 
  1474 
  1475     |mySize    "{ Class: SmallInteger }"
  1475     |mySize    "{ Class: SmallInteger }"
  1476      otherSize "{ Class: SmallInteger }" 
  1476      otherSize "{ Class: SmallInteger }"
  1477      n         "{ Class: SmallInteger }" 
  1477      n         "{ Class: SmallInteger }"
  1478      c1 c2|
  1478      c1 c2|
  1479 
  1479 
  1480     mySize := self size.
  1480     mySize := self size.
  1481     otherSize := aString string size.
  1481     otherSize := aString string size.
  1482     n := mySize min:otherSize.
  1482     n := mySize min:otherSize.
  1483 
  1483 
  1484     1 to:n do:[:index |
  1484     1 to:n do:[:index |
  1485         c1 := self at:index.
  1485 	c1 := self at:index.
  1486         c2 := aString at:index.
  1486 	c2 := aString at:index.
  1487         (c1 == c2 or:[c1 = c2]) ifFalse:[^ c1 < c2].
  1487 	(c1 == c2 or:[c1 = c2]) ifFalse:[^ c1 < c2].
  1488     ].
  1488     ].
  1489     ^ mySize < otherSize
  1489     ^ mySize < otherSize
  1490 !
  1490 !
  1491 
  1491 
  1492 = aString
  1492 = aString
  1493     "Compare the receiver with the argument and return true if the
  1493     "Compare the receiver with the argument and return true if the
  1494      receiver is equal to the argument. Otherwise return false.
  1494      receiver is equal to the argument. Otherwise return false.
  1495 
  1495 
  1496      This compare does NOT ignore case differences, 
  1496      This compare does NOT ignore case differences,
  1497      therefore 'foo' = 'Foo' will return false.
  1497      therefore 'foo' = 'Foo' will return false.
  1498      Since this is incompatible to ST-80 (at least, V2.x) , this may change."
  1498      Since this is incompatible to ST-80 (at least, V2.x) , this may change."
  1499 
  1499 
  1500     |mySize    "{ Class: SmallInteger }"
  1500     |mySize    "{ Class: SmallInteger }"
  1501      otherSize |
  1501      otherSize |
  1502 
  1502 
  1503     (aString isString or:[aString species == self species]) ifFalse:[
  1503     (aString isString or:[aString species == self species]) ifFalse:[
  1504         ^ false
  1504 	^ false
  1505     ].
  1505     ].
  1506     mySize := self size.
  1506     mySize := self size.
  1507     otherSize := aString size.
  1507     otherSize := aString size.
  1508     mySize == otherSize ifFalse:[^ false].
  1508     mySize == otherSize ifFalse:[^ false].
  1509 
  1509 
  1510     1 to:mySize do:[:index |
  1510     1 to:mySize do:[:index |
  1511         (self at:index) = (aString at:index) ifFalse:[^ false].
  1511 	(self at:index) = (aString at:index) ifFalse:[^ false].
  1512     ].
  1512     ].
  1513     ^ true
  1513     ^ true
  1514 
  1514 
  1515     "
  1515     "
  1516      'foo' = 'Foo'  
  1516      'foo' = 'Foo'
  1517      'foo' = 'bar'  
  1517      'foo' = 'bar'
  1518      'foo' = 'foo'           
  1518      'foo' = 'foo'
  1519      'foo' = 'foo' asText    
  1519      'foo' = 'foo' asText
  1520      'foo' asText = 'foo'    
  1520      'foo' asText = 'foo'
  1521      'foo' asText = 'foo' asText  
  1521      'foo' asText = 'foo' asText
  1522     "
  1522     "
  1523 
  1523 
  1524     "Modified: 22.4.1996 / 15:53:58 / cg"
  1524     "Modified: 22.4.1996 / 15:53:58 / cg"
  1525 !
  1525 !
  1526 
  1526 
  1527 > aString
  1527 > aString
  1528     "Compare the receiver with the argument and return true if the
  1528     "Compare the receiver with the argument and return true if the
  1529      receiver is greater than the argument. Otherwise return false.
  1529      receiver is greater than the argument. Otherwise return false.
  1530      This comparison is based on the elements ascii code - 
  1530      This comparison is based on the elements ascii code -
  1531      i.e. upper/lowercase & upper/lowercase & national characters are NOT treated specially."
  1531      i.e. upper/lowercase & upper/lowercase & national characters are NOT treated specially."
  1532 
  1532 
  1533     |mySize    "{ Class: SmallInteger }"
  1533     |mySize    "{ Class: SmallInteger }"
  1534      otherSize "{ Class: SmallInteger }" 
  1534      otherSize "{ Class: SmallInteger }"
  1535      n         "{ Class: SmallInteger }" 
  1535      n         "{ Class: SmallInteger }"
  1536      c1 c2|
  1536      c1 c2|
  1537 
  1537 
  1538     mySize := self size.
  1538     mySize := self size.
  1539     otherSize := aString string size.
  1539     otherSize := aString string size.
  1540     n := mySize min:otherSize.
  1540     n := mySize min:otherSize.
  1541 
  1541 
  1542     1 to:n do:[:index |
  1542     1 to:n do:[:index |
  1543         c1 := self at:index.
  1543 	c1 := self at:index.
  1544         c2 := aString at:index.
  1544 	c2 := aString at:index.
  1545         (c1 == c2 or:[c1 = c2]) ifFalse:[^ c1 > c2].
  1545 	(c1 == c2 or:[c1 = c2]) ifFalse:[^ c1 > c2].
  1546     ].
  1546     ].
  1547     ^ mySize > otherSize
  1547     ^ mySize > otherSize
  1548 
  1548 
  1549     "Modified: 22.4.1996 / 15:55:00 / cg"
  1549     "Modified: 22.4.1996 / 15:55:00 / cg"
  1550 !
  1550 !
  1551 
  1551 
  1552 compareCaselessWith:aString
  1552 compareCaselessWith:aString
  1553     "Compare the receiver against the argument, ignoreing case.
  1553     "Compare the receiver against the argument, ignoreing case.
  1554      Return 1 if the receiver is greater, 0 if equal and -1 if less than the argument. 
  1554      Return 1 if the receiver is greater, 0 if equal and -1 if less than the argument.
  1555 
  1555 
  1556      This comparison is based on the elements ascii code - 
  1556      This comparison is based on the elements ascii code -
  1557      i.e. national characters are NOT treated specially.
  1557      i.e. national characters are NOT treated specially.
  1558      'foo' compareWith: 'Foo' will return 0"
  1558      'foo' compareWith: 'Foo' will return 0"
  1559 
  1559 
  1560     |mySize    "{ Class: SmallInteger }"
  1560     |mySize    "{ Class: SmallInteger }"
  1561      otherSize "{ Class: SmallInteger }" 
  1561      otherSize "{ Class: SmallInteger }"
  1562      n         "{ Class: SmallInteger }" 
  1562      n         "{ Class: SmallInteger }"
  1563      c1 c2|
  1563      c1 c2|
  1564 
  1564 
  1565     mySize := self size.
  1565     mySize := self size.
  1566     otherSize := aString string size.
  1566     otherSize := aString string size.
  1567     n := mySize min:otherSize.
  1567     n := mySize min:otherSize.
  1568 
  1568 
  1569     1 to:n do:[:index |
  1569     1 to:n do:[:index |
  1570         c1 := (self at:index) asLowercase.
  1570 	c1 := (self at:index) asLowercase.
  1571         c2 := (aString at:index) asLowercase.
  1571 	c2 := (aString at:index) asLowercase.
  1572         c1 > c2 ifTrue:[^ 1].
  1572 	c1 > c2 ifTrue:[^ 1].
  1573         c1 < c2 ifTrue:[^ -1].
  1573 	c1 < c2 ifTrue:[^ -1].
  1574     ].
  1574     ].
  1575     mySize > otherSize ifTrue:[^ 1].
  1575     mySize > otherSize ifTrue:[^ 1].
  1576     mySize < otherSize ifTrue:[^ -1].
  1576     mySize < otherSize ifTrue:[^ -1].
  1577     ^ 0
  1577     ^ 0
  1578 
  1578 
  1579     "Modified: 22.4.1996 / 15:56:07 / cg"
  1579     "Modified: 22.4.1996 / 15:56:07 / cg"
  1580 !
  1580 !
  1581 
  1581 
  1582 compareWith:aString
  1582 compareWith:aString
  1583     "Compare the receiver with the argument and return 1 if the receiver is
  1583     "Compare the receiver with the argument and return 1 if the receiver is
  1584      greater, 0 if equal and -1 if less than the argument. 
  1584      greater, 0 if equal and -1 if less than the argument.
  1585      This comparison is based on the elements ascii code - 
  1585      This comparison is based on the elements ascii code -
  1586      i.e. upper/lowercase & national characters are NOT treated specially.
  1586      i.e. upper/lowercase & national characters are NOT treated specially.
  1587      'foo' compareWith: 'Foo' will return 1.
  1587      'foo' compareWith: 'Foo' will return 1.
  1588      while 'foo' sameAs:'Foo' will return true"
  1588      while 'foo' sameAs:'Foo' will return true"
  1589 
  1589 
  1590     |mySize    "{ Class: SmallInteger }"
  1590     |mySize    "{ Class: SmallInteger }"
  1591      otherSize "{ Class: SmallInteger }" 
  1591      otherSize "{ Class: SmallInteger }"
  1592      n         "{ Class: SmallInteger }" 
  1592      n         "{ Class: SmallInteger }"
  1593      c1 c2|
  1593      c1 c2|
  1594 
  1594 
  1595     mySize := self size.
  1595     mySize := self size.
  1596     otherSize := aString string size.
  1596     otherSize := aString string size.
  1597     n := mySize min:otherSize.
  1597     n := mySize min:otherSize.
  1598 
  1598 
  1599     1 to:n do:[:index |
  1599     1 to:n do:[:index |
  1600         c1 := self at:index.
  1600 	c1 := self at:index.
  1601         c2 := aString at:index.
  1601 	c2 := aString at:index.
  1602         c1 > c2 ifTrue:[^ 1].
  1602 	c1 > c2 ifTrue:[^ 1].
  1603         c1 < c2 ifTrue:[^ -1].
  1603 	c1 < c2 ifTrue:[^ -1].
  1604     ].
  1604     ].
  1605     mySize > otherSize ifTrue:[^ 1].
  1605     mySize > otherSize ifTrue:[^ 1].
  1606     mySize < otherSize ifTrue:[^ -1].
  1606     mySize < otherSize ifTrue:[^ -1].
  1607     ^ 0
  1607     ^ 0
  1608 
  1608 
  1619     int l;
  1619     int l;
  1620 
  1620 
  1621     cp = __stringVal(self);
  1621     cp = __stringVal(self);
  1622     l = __stringSize(self);
  1622     l = __stringSize(self);
  1623     if (__qClass(self) != @global(String)) {
  1623     if (__qClass(self) != @global(String)) {
  1624         int n = __OBJS2BYTES__(__intVal(__ClassInstPtr(__qClass(self))->c_ninstvars));
  1624 	int n = __OBJS2BYTES__(__intVal(__ClassInstPtr(__qClass(self))->c_ninstvars));
  1625 
  1625 
  1626         cp += n;
  1626 	cp += n;
  1627         l -= n;
  1627 	l -= n;
  1628     }
  1628     }
  1629 
  1629 
  1630     /*
  1630     /*
  1631      * this is the dragon-book algorithm 
  1631      * this is the dragon-book algorithm
  1632      */
  1632      */
  1633 
  1633 
  1634     val = 0;
  1634     val = 0;
  1635     switch (l) {
  1635     switch (l) {
  1636     default:
  1636     default:
  1637         for (cp0 = cp, cp += l - 1; cp >= cp0; cp--) {
  1637 	for (cp0 = cp, cp += l - 1; cp >= cp0; cp--) {
  1638             val = (val << 4) + *cp;
  1638 	    val = (val << 4) + *cp;
  1639             if (g = (val & 0xF0000000)) {
  1639 	    if (g = (val & 0xF0000000)) {
  1640                 val ^= g >> 24;
  1640 		val ^= g >> 24;
  1641                 val ^= g;
  1641 		val ^= g;
  1642             }
  1642 	    }
  1643         }
  1643 	}
  1644         break;
  1644 	break;
  1645     case 7:
  1645     case 7:
  1646         val = cp[6] << 4;
  1646 	val = cp[6] << 4;
  1647     case 6:
  1647     case 6:
  1648         val = (val + cp[5]) << 4;
  1648 	val = (val + cp[5]) << 4;
  1649     case 5:
  1649     case 5:
  1650         val = (val + cp[4]) << 4;
  1650 	val = (val + cp[4]) << 4;
  1651     case 4:
  1651     case 4:
  1652         val = (val + cp[3]) << 4;
  1652 	val = (val + cp[3]) << 4;
  1653     case 3:
  1653     case 3:
  1654         val = (val + cp[2]) << 4;
  1654 	val = (val + cp[2]) << 4;
  1655     case 2:
  1655     case 2:
  1656         val = (val + cp[1]) << 4;
  1656 	val = (val + cp[1]) << 4;
  1657     case 1:
  1657     case 1:
  1658         val = val + cp[0];
  1658 	val = val + cp[0];
  1659     case 0:
  1659     case 0:
  1660         break;
  1660 	break;
  1661     }
  1661     }
  1662 
  1662 
  1663     /*
  1663     /*
  1664      * multiply by large prime to spread values
  1664      * multiply by large prime to spread values
  1665      * This speeds up Set and Dictionary by a factor of 10!
  1665      * This speeds up Set and Dictionary by a factor of 10!
  1669 %}
  1669 %}
  1670 
  1670 
  1671 !
  1671 !
  1672 
  1672 
  1673 sameAs:aString
  1673 sameAs:aString
  1674     "Compare the receiver with the argument like =, but ignore case differences. 
  1674     "Compare the receiver with the argument like =, but ignore case differences.
  1675      Return true or false."
  1675      Return true or false."
  1676 
  1676 
  1677     |mySize "{ Class: SmallInteger }"
  1677     |mySize "{ Class: SmallInteger }"
  1678      otherSize c1 c2|
  1678      otherSize c1 c2|
  1679 
  1679 
  1682     mySize := self size.
  1682     mySize := self size.
  1683     otherSize := aString string size.
  1683     otherSize := aString string size.
  1684     mySize == otherSize ifFalse:[^ false].
  1684     mySize == otherSize ifFalse:[^ false].
  1685 
  1685 
  1686     1 to:mySize do:[:index |
  1686     1 to:mySize do:[:index |
  1687         c1 := self at:index.
  1687 	c1 := self at:index.
  1688         c2 := aString at:index.
  1688 	c2 := aString at:index.
  1689         c1 == c2 ifFalse:[
  1689 	c1 == c2 ifFalse:[
  1690             (c1 sameAs:c2) ifFalse:[^ false].
  1690 	    (c1 sameAs:c2) ifFalse:[^ false].
  1691         ]
  1691 	]
  1692     ].
  1692     ].
  1693     ^ true
  1693     ^ true
  1694 
  1694 
  1695     "
  1695     "
  1696      'foo' sameAs: 'Foo'   
  1696      'foo' sameAs: 'Foo'
  1697      'foo' sameAs: 'bar' 
  1697      'foo' sameAs: 'bar'
  1698      'foo' sameAs: 'foo'   
  1698      'foo' sameAs: 'foo'
  1699     "
  1699     "
  1700 
  1700 
  1701     "Modified: 22.4.1996 / 15:56:17 / cg"
  1701     "Modified: 22.4.1996 / 15:56:17 / cg"
  1702 !
  1702 !
  1703 
  1703 
  1705     "Compare the receiver with the argument.
  1705     "Compare the receiver with the argument.
  1706      If ignoreCase is true, this is the same as #sameAs:,
  1706      If ignoreCase is true, this is the same as #sameAs:,
  1707      if false, this is the same as #=."
  1707      if false, this is the same as #=."
  1708 
  1708 
  1709     ignoreCase ifTrue:[
  1709     ignoreCase ifTrue:[
  1710         ^ self sameAs:aString
  1710 	^ self sameAs:aString
  1711     ].
  1711     ].
  1712     ^ self = aString
  1712     ^ self = aString
  1713 
  1713 
  1714     "
  1714     "
  1715      'foo' sameAs:'Foo' ignoreCase:false  
  1715      'foo' sameAs:'Foo' ignoreCase:false
  1716      'foo' sameAs:'foo' ignoreCase:true   
  1716      'foo' sameAs:'foo' ignoreCase:true
  1717     "
  1717     "
  1718 
  1718 
  1719 !
  1719 !
  1720 
  1720 
  1721 sameCharacters:aString
  1721 sameCharacters:aString
  1728     n := self size.
  1728     n := self size.
  1729     n := n min:(aString string size).
  1729     n := n min:(aString string size).
  1730 
  1730 
  1731     cnt := 0.
  1731     cnt := 0.
  1732     1 to:n do:[:index |
  1732     1 to:n do:[:index |
  1733         c1 := self at:index.
  1733 	c1 := self at:index.
  1734         c2 := aString at:index.
  1734 	c2 := aString at:index.
  1735         ((c1 == c2)
  1735 	((c1 == c2)
  1736         or:[c1 asLowercase = c2 asLowercase]) ifTrue:[
  1736 	or:[c1 asLowercase = c2 asLowercase]) ifTrue:[
  1737             cnt := cnt + 1
  1737 	    cnt := cnt + 1
  1738         ]
  1738 	]
  1739     ].
  1739     ].
  1740     ^ cnt
  1740     ^ cnt
  1741 
  1741 
  1742     "
  1742     "
  1743      'foobarbaz' sameCharacters: 'foo'   
  1743      'foobarbaz' sameCharacters: 'foo'
  1744      'foobarbaz' sameCharacters: 'Foo'   
  1744      'foobarbaz' sameCharacters: 'Foo'
  1745      'foobarbaz' sameCharacters: 'baz'   
  1745      'foobarbaz' sameCharacters: 'baz'
  1746     "
  1746     "
  1747 !
  1747 !
  1748 
  1748 
  1749 sameEmphasisAs:aStringOrText
  1749 sameEmphasisAs:aStringOrText
  1750     "compare the receivers and the arguments emphasis"
  1750     "compare the receivers and the arguments emphasis"
  1751 
  1751 
  1752     ^ self emphasis = aStringOrText emphasis
  1752     ^ self emphasis = aStringOrText emphasis
  1753 
  1753 
  1754     "
  1754     "
  1755      'hello' asText sameEmphasisAs: 'hello'         
  1755      'hello' asText sameEmphasisAs: 'hello'
  1756      'hello' asText sameEmphasisAs: 'hello' asText  
  1756      'hello' asText sameEmphasisAs: 'hello' asText
  1757      'hello' asText allBold sameEmphasisAs: 'hello' 
  1757      'hello' asText allBold sameEmphasisAs: 'hello'
  1758      'hello' asText allBold sameEmphasisAs: 'fooba' asText allBold  
  1758      'hello' asText allBold sameEmphasisAs: 'fooba' asText allBold
  1759      'hello' asText allBold sameEmphasisAs: 'fooba' asText allItalic  
  1759      'hello' asText allBold sameEmphasisAs: 'fooba' asText allItalic
  1760     "
  1760     "
  1761 
  1761 
  1762 
  1762 
  1763 !
  1763 !
  1764 
  1764 
  1769     (self string = aStringOrText string) ifFalse:[^ false].
  1769     (self string = aStringOrText string) ifFalse:[^ false].
  1770     self hasChangeOfEmphasis = aStringOrText hasChangeOfEmphasis ifFalse:[^ false].
  1770     self hasChangeOfEmphasis = aStringOrText hasChangeOfEmphasis ifFalse:[^ false].
  1771     ^ self emphasis = aStringOrText emphasis
  1771     ^ self emphasis = aStringOrText emphasis
  1772 
  1772 
  1773     "
  1773     "
  1774      'hello' asText sameEmphasisAs: 'hello'         
  1774      'hello' asText sameEmphasisAs: 'hello'
  1775      'hello' asText sameEmphasisAs: 'hello' asText  
  1775      'hello' asText sameEmphasisAs: 'hello' asText
  1776      'hello' asText allBold sameEmphasisAs: 'hello' 
  1776      'hello' asText allBold sameEmphasisAs: 'hello'
  1777      'hello' asText allBold sameEmphasisAs: 'fooba' asText allBold  
  1777      'hello' asText allBold sameEmphasisAs: 'fooba' asText allBold
  1778      'hello' asText allBold sameEmphasisAs: 'fooba' asText allItalic  
  1778      'hello' asText allBold sameEmphasisAs: 'fooba' asText allItalic
  1779 
  1779 
  1780      'hello' sameEmphasisAs: 'hello' asText         
  1780      'hello' sameEmphasisAs: 'hello' asText
  1781      'hello' sameEmphasisAs: 'hello' asText allBold  
  1781      'hello' sameEmphasisAs: 'hello' asText allBold
  1782      'hello' sameEmphasisAs: 'fooba'                 
  1782      'hello' sameEmphasisAs: 'fooba'
  1783      'hello' sameEmphasisAs: 'fooba' asText          
  1783      'hello' sameEmphasisAs: 'fooba' asText
  1784      'hello' sameEmphasisAs: 'fooba' asText allBold  
  1784      'hello' sameEmphasisAs: 'fooba' asText allBold
  1785      'hello' sameEmphasisAs: 'fooba' asText allItalic  
  1785      'hello' sameEmphasisAs: 'fooba' asText allItalic
  1786 
  1786 
  1787      'hello' asText sameStringAndEmphasisAs: 'hello'           
  1787      'hello' asText sameStringAndEmphasisAs: 'hello'
  1788      'hello' asText sameStringAndEmphasisAs: 'hello' asText    
  1788      'hello' asText sameStringAndEmphasisAs: 'hello' asText
  1789      'hello' asText allBold sameStringAndEmphasisAs: 'hello'   
  1789      'hello' asText allBold sameStringAndEmphasisAs: 'hello'
  1790      'hello' asText allBold sameStringAndEmphasisAs: 'fooba' asText allBold  
  1790      'hello' asText allBold sameStringAndEmphasisAs: 'fooba' asText allBold
  1791      'hello' asText allBold sameStringAndEmphasisAs: 'fooba' asText allItalic  
  1791      'hello' asText allBold sameStringAndEmphasisAs: 'fooba' asText allItalic
  1792 
  1792 
  1793      'hello' sameStringAndEmphasisAs: 'hello' asText                         
  1793      'hello' sameStringAndEmphasisAs: 'hello' asText
  1794      'hello' sameStringAndEmphasisAs: 'hello' asText allBold                 
  1794      'hello' sameStringAndEmphasisAs: 'hello' asText allBold
  1795      'hello' sameStringAndEmphasisAs: 'fooba'                                
  1795      'hello' sameStringAndEmphasisAs: 'fooba'
  1796      'hello' sameStringAndEmphasisAs: 'fooba' asText                         
  1796      'hello' sameStringAndEmphasisAs: 'fooba' asText
  1797      'hello' sameStringAndEmphasisAs: 'fooba' asText allBold  
  1797      'hello' sameStringAndEmphasisAs: 'fooba' asText allBold
  1798      'hello' sameStringAndEmphasisAs: 'fooba' asText allItalic  
  1798      'hello' sameStringAndEmphasisAs: 'fooba' asText allItalic
  1799     "
  1799     "
  1800 ! !
  1800 ! !
  1801 
  1801 
  1802 !CharacterArray methodsFor:'converting'!
  1802 !CharacterArray methodsFor:'converting'!
  1803 
  1803 
  1808      asCollectionOfWords."
  1808      asCollectionOfWords."
  1809 
  1809 
  1810     ^ self asCollectionOfWords asArray
  1810     ^ self asCollectionOfWords asArray
  1811 
  1811 
  1812     "
  1812     "
  1813      '1 one two three four 5 five' asArrayOfSubstrings  
  1813      '1 one two three four 5 five' asArrayOfSubstrings
  1814      '1
  1814      '1
  1815 one 
  1815 one
  1816         two three four 5 five' asArrayOfSubstrings       
  1816 	two three four 5 five' asArrayOfSubstrings
  1817     "
  1817     "
  1818 !
  1818 !
  1819 
  1819 
  1820 asCollectionOfLines
  1820 asCollectionOfLines
  1821     "return a collection containing the lines (separated by cr) 
  1821     "return a collection containing the lines (separated by cr)
  1822      of the receiver. If multiple cr's occur in a row, the result will
  1822      of the receiver. If multiple cr's occur in a row, the result will
  1823      contain empty strings."
  1823      contain empty strings."
  1824 
  1824 
  1825     ^ self asCollectionOfSubstringsSeparatedBy:Character cr
  1825     ^ self asCollectionOfSubstringsSeparatedBy:Character cr
  1826 
  1826 
  1827     "
  1827     "
  1828      '1 one\2 two\3 three\4 four\5 five' withCRs asCollectionOfLines
  1828      '1 one\2 two\3 three\4 four\5 five' withCRs asCollectionOfLines
  1829      '1 one\\\\2 two\3 three' withCRs asCollectionOfLines  
  1829      '1 one\\\\2 two\3 three' withCRs asCollectionOfLines
  1830     "
  1830     "
  1831 !
  1831 !
  1832 
  1832 
  1833 asCollectionOfSubstringsSeparatedBy:aCharacter
  1833 asCollectionOfSubstringsSeparatedBy:aCharacter
  1834     "return a collection containing the lines (separated by aCharacter) 
  1834     "return a collection containing the lines (separated by aCharacter)
  1835      of the receiver. If aCharacter occurs multiple times in a row, 
  1835      of the receiver. If aCharacter occurs multiple times in a row,
  1836      the result will contain empty strings."
  1836      the result will contain empty strings."
  1837 
  1837 
  1838     ^ self asCollectionOfSubCollectionsSeparatedBy:aCharacter
  1838     ^ self asCollectionOfSubCollectionsSeparatedBy:aCharacter
  1839 
  1839 
  1840     "
  1840     "
  1841      '1 one:2 two:3 three:4 four:5 five' withCRs asCollectionOfSubstringsSeparatedBy:$: 
  1841      '1 one:2 two:3 three:4 four:5 five' withCRs asCollectionOfSubstringsSeparatedBy:$:
  1842      '1 one 2 two 3 three 4 four 5 five' withCRs asCollectionOfSubstringsSeparatedBy:Character space
  1842      '1 one 2 two 3 three 4 four 5 five' withCRs asCollectionOfSubstringsSeparatedBy:Character space
  1843     "
  1843     "
  1844 !
  1844 !
  1845 
  1845 
  1846 asCollectionOfSubstringsSeparatedByAll:aSeparatorString
  1846 asCollectionOfSubstringsSeparatedByAll:aSeparatorString
  1847     "return a collection containing the lines (separated by aSeparatorString) 
  1847     "return a collection containing the lines (separated by aSeparatorString)
  1848      of the receiver. If aSeparatorString occurs multiple times in a row, 
  1848      of the receiver. If aSeparatorString occurs multiple times in a row,
  1849      the result will contain empty strings."
  1849      the result will contain empty strings."
  1850 
  1850 
  1851     ^ self asCollectionOfSubCollectionsSeparatedByAll:aSeparatorString
  1851     ^ self asCollectionOfSubCollectionsSeparatedByAll:aSeparatorString
  1852 
  1852 
  1853     "
  1853     "
  1854      '1::2::3::4::5::' asCollectionOfSubstringsSeparatedByAll:'::' 
  1854      '1::2::3::4::5::' asCollectionOfSubstringsSeparatedByAll:'::'
  1855     "
  1855     "
  1856 !
  1856 !
  1857 
  1857 
  1858 asCollectionOfSubstringsSeparatedByAny:aCollectionOfSeparators
  1858 asCollectionOfSubstringsSeparatedByAny:aCollectionOfSeparators
  1859     "return a collection containing the words (separated by any character
  1859     "return a collection containing the words (separated by any character
  1862 
  1862 
  1863     ^ self asCollectionOfSubCollectionsSeparatedByAny:aCollectionOfSeparators
  1863     ^ self asCollectionOfSubCollectionsSeparatedByAny:aCollectionOfSeparators
  1864 
  1864 
  1865     "
  1865     "
  1866      'hello:world:isnt:this nice' asCollectionOfSubstringsSeparatedByAny:#($:)
  1866      'hello:world:isnt:this nice' asCollectionOfSubstringsSeparatedByAny:#($:)
  1867      'hello:world:isnt:this nice' asCollectionOfSubstringsSeparatedByAny:':' 
  1867      'hello:world:isnt:this nice' asCollectionOfSubstringsSeparatedByAny:':'
  1868      'hello:world:isnt:this nice' asCollectionOfSubstringsSeparatedByAny:(Array with:$: with:Character space) 
  1868      'hello:world:isnt:this nice' asCollectionOfSubstringsSeparatedByAny:(Array with:$: with:Character space)
  1869      'hello:world:isnt:this nice' asCollectionOfSubstringsSeparatedByAny:': ' 
  1869      'hello:world:isnt:this nice' asCollectionOfSubstringsSeparatedByAny:': '
  1870      'h1e2l3l4o' asCollectionOfSubstringsSeparatedByAny:($1 to: $9) 
  1870      'h1e2l3l4o' asCollectionOfSubstringsSeparatedByAny:($1 to: $9)
  1871     "
  1871     "
  1872 !
  1872 !
  1873 
  1873 
  1874 asCollectionOfWords
  1874 asCollectionOfWords
  1875     "return a collection containing the words (separated by whitespace) 
  1875     "return a collection containing the words (separated by whitespace)
  1876      of the receiver. Multiple occurences of whitespace characters will
  1876      of the receiver. Multiple occurrences of whitespace characters will
  1877      be treated like one - i.e. whitespace is skipped."
  1877      be treated like one - i.e. whitespace is skipped."
  1878 
  1878 
  1879     |words|
  1879     |words|
  1880 
  1880 
  1881     words := OrderedCollection new.
  1881     words := OrderedCollection new.
  1890      '      ' asCollectionOfWords
  1890      '      ' asCollectionOfWords
  1891     "
  1891     "
  1892 !
  1892 !
  1893 
  1893 
  1894 asCollectionOfWordsDo:aBlock
  1894 asCollectionOfWordsDo:aBlock
  1895     "evaluate aBlock for each word (separated by whitespace) of the receiver. 
  1895     "evaluate aBlock for each word (separated by whitespace) of the receiver.
  1896      Multiple occurences of whitespace characters will be treated like one 
  1896      Multiple occurrences of whitespace characters will be treated like one
  1897      - i.e. whitespace is skipped.
  1897      - i.e. whitespace is skipped.
  1898      Returns the number of words (i.e. the number of invocations of aBlock)."
  1898      Returns the number of words (i.e. the number of invocations of aBlock)."
  1899 
  1899 
  1900     |count  "{ Class:SmallInteger }"
  1900     |count  "{ Class:SmallInteger }"
  1901      start  "{ Class:SmallInteger }" 
  1901      start  "{ Class:SmallInteger }"
  1902      stop   "{ Class:SmallInteger }" 
  1902      stop   "{ Class:SmallInteger }"
  1903      mySize "{ Class:SmallInteger }"|
  1903      mySize "{ Class:SmallInteger }"|
  1904 
  1904 
  1905     count := 0.
  1905     count := 0.
  1906     start := 1.
  1906     start := 1.
  1907     mySize := self size.
  1907     mySize := self size.
  1908     [start <= mySize] whileTrue:[
  1908     [start <= mySize] whileTrue:[
  1909         start := self indexOfNonSeparatorStartingAt:start.
  1909 	start := self indexOfNonSeparatorStartingAt:start.
  1910         start == 0 ifTrue:[
  1910 	start == 0 ifTrue:[
  1911             ^ count
  1911 	    ^ count
  1912         ].
  1912 	].
  1913         stop := self indexOfSeparatorStartingAt:start.
  1913 	stop := self indexOfSeparatorStartingAt:start.
  1914         stop == 0 ifTrue:[
  1914 	stop == 0 ifTrue:[
  1915             aBlock value:(self copyFrom:start to:mySize).
  1915 	    aBlock value:(self copyFrom:start to:mySize).
  1916             ^ count + 1
  1916 	    ^ count + 1
  1917         ].
  1917 	].
  1918         aBlock value:(self copyFrom:start to:(stop - 1)).
  1918 	aBlock value:(self copyFrom:start to:(stop - 1)).
  1919         start := stop.
  1919 	start := stop.
  1920         count := count + 1
  1920 	count := count + 1
  1921     ].
  1921     ].
  1922     ^ count
  1922     ^ count
  1923 
  1923 
  1924     "
  1924     "
  1925      'hello world isnt this nice' asCollectionOfWordsDo:[:w | Transcript showCR:w]
  1925      'hello world isnt this nice' asCollectionOfWordsDo:[:w | Transcript showCR:w]
  1929      '      ' asCollectionOfWordsDo:[:w | Transcript showCR:w]
  1929      '      ' asCollectionOfWordsDo:[:w | Transcript showCR:w]
  1930     "
  1930     "
  1931 !
  1931 !
  1932 
  1932 
  1933 asComposedText
  1933 asComposedText
  1934     "ST-80 compatibility 
  1934     "ST-80 compatibility
  1935      - ST/X does not (as today) support composedTexts."
  1935      - ST/X does not (as today) support composedTexts."
  1936 
  1936 
  1937     ^ ComposedText fromString:self string
  1937     ^ ComposedText fromString:self string
  1938 
  1938 
  1939     "Modified: 27.4.1996 / 13:30:30 / cg"
  1939     "Modified: 27.4.1996 / 13:30:30 / cg"
  1947     "Modified: 20.5.1996 / 09:38:15 / cg"
  1947     "Modified: 20.5.1996 / 09:38:15 / cg"
  1948 !
  1948 !
  1949 
  1949 
  1950 asFixedPoint
  1950 asFixedPoint
  1951     "read a fixedPoint number from the receiver.
  1951     "read a fixedPoint number from the receiver.
  1952      Notice, that errors may occur during the read, 
  1952      Notice, that errors may occur during the read,
  1953      so you better setup some signal handler when using this method."
  1953      so you better setup some signal handler when using this method."
  1954 
  1954 
  1955     ^ FixedPoint readFromString:self
  1955     ^ FixedPoint readFromString:self
  1956 
  1956 
  1957     "
  1957     "
  1958      '0.123' asFixedPoint    
  1958      '0.123' asFixedPoint
  1959      '12345' asFixedPoint    
  1959      '12345' asFixedPoint
  1960      '(1/5)' asFixedPoint
  1960      '(1/5)' asFixedPoint
  1961      'foo' asFixedPoint
  1961      'foo' asFixedPoint
  1962      Object errorSignal handle:[:ex | ex return:0] do:['foo' asFixedPoint] 
  1962      Object errorSignal handle:[:ex | ex return:0] do:['foo' asFixedPoint]
  1963     "
  1963     "
  1964 
  1964 
  1965     "Modified: / 25.10.1997 / 15:19:00 / cg"
  1965     "Modified: / 25.10.1997 / 15:19:00 / cg"
  1966 !
  1966 !
  1967 
  1967 
  1968 asFixedPoint:scale
  1968 asFixedPoint:scale
  1969     "read a fixedPoint number with scale number of post-decimal digits
  1969     "read a fixedPoint number with scale number of post-decimal digits
  1970      from the receiver. Scale controls the number of displayed digits,
  1970      from the receiver. Scale controls the number of displayed digits,
  1971      not the number of actually valid digits.
  1971      not the number of actually valid digits.
  1972      Notice, that errors may occur during the read, 
  1972      Notice, that errors may occur during the read,
  1973      so you better setup some signal handler when using this method."
  1973      so you better setup some signal handler when using this method."
  1974 
  1974 
  1975     ^ (FixedPoint readFromString:self) scale:scale
  1975     ^ (FixedPoint readFromString:self) scale:scale
  1976 
  1976 
  1977     "
  1977     "
  1978      '0.123' asFixedPoint:2     
  1978      '0.123' asFixedPoint:2
  1979      '123456' asFixedPoint:2    
  1979      '123456' asFixedPoint:2
  1980      ('3.14157' asFixedPoint:1) asFixedPoint:5    
  1980      ('3.14157' asFixedPoint:1) asFixedPoint:5
  1981      '3.14157' asFixedPoint:2    
  1981      '3.14157' asFixedPoint:2
  1982      'foo' asFixedPoint:2    
  1982      'foo' asFixedPoint:2
  1983     "
  1983     "
  1984 
  1984 
  1985     "Modified: / 25.10.1997 / 15:21:57 / cg"
  1985     "Modified: / 25.10.1997 / 15:21:57 / cg"
  1986 !
  1986 !
  1987 
  1987 
  1988 asFloat
  1988 asFloat
  1989     "read a float number from the receiver.
  1989     "read a float number from the receiver.
  1990      Notice, that errors may occur during the read, 
  1990      Notice, that errors may occur during the read,
  1991      so you better setup some exception handler when using this method."
  1991      so you better setup some exception handler when using this method."
  1992 
  1992 
  1993     ^ (Number readFromString:self) asFloat
  1993     ^ (Number readFromString:self) asFloat
  1994 
  1994 
  1995     "
  1995     "
  1996      '0.123' asFloat 
  1996      '0.123' asFloat
  1997      '12345' asFloat
  1997      '12345' asFloat
  1998      '(1/5)' asFloat
  1998      '(1/5)' asFloat
  1999      Object errorSignal handle:[:ex | ex return:0] do:['foo' asFloat] 
  1999      Object errorSignal handle:[:ex | ex return:0] do:['foo' asFloat]
  2000     "
  2000     "
  2001 !
  2001 !
  2002 
  2002 
  2003 asInteger
  2003 asInteger
  2004     "read an integer from the receiver.
  2004     "read an integer from the receiver.
  2005      Notice, that errors may occur during the read, 
  2005      Notice, that errors may occur during the read,
  2006      so you better setup some exception handler when using this method."
  2006      so you better setup some exception handler when using this method."
  2007 
  2007 
  2008     ^ Integer readFromString:self
  2008     ^ Integer readFromString:self
  2009 
  2009 
  2010     "
  2010     "
  2011      '12345678901234567890' asInteger
  2011      '12345678901234567890' asInteger
  2012      '-1234' asInteger
  2012      '-1234' asInteger
  2013      '0.123' asInteger   <- reader stops at ., returning 0 here
  2013      '0.123' asInteger   <- reader stops at ., returning 0 here
  2014      '0.123' asNumber    <- returns what you expect
  2014      '0.123' asNumber    <- returns what you expect
  2015      Object errorSignal handle:[:ex | ex return:0] do:['foo' asInteger] 
  2015      Object errorSignal handle:[:ex | ex return:0] do:['foo' asInteger]
  2016     "
  2016     "
  2017 !
  2017 !
  2018 
  2018 
  2019 asLowercase
  2019 asLowercase
  2020     "return a copy of myself in lowercase letters"
  2020     "return a copy of myself in lowercase letters"
  2025     mySize := self size.
  2025     mySize := self size.
  2026     newStr := self species new:mySize.
  2026     newStr := self species new:mySize.
  2027     bitsPerCharacter := newStr bitsPerCharacter.
  2027     bitsPerCharacter := newStr bitsPerCharacter.
  2028 
  2028 
  2029     1 to:mySize do:[:i |
  2029     1 to:mySize do:[:i |
  2030         c := (self at:i) asLowercase.
  2030 	c := (self at:i) asLowercase.
  2031         c bitsPerCharacter > bitsPerCharacter ifTrue:[
  2031 	c bitsPerCharacter > bitsPerCharacter ifTrue:[
  2032             newStr := c stringSpecies fromString:newStr.    
  2032 	    newStr := c stringSpecies fromString:newStr.
  2033         ].
  2033 	].
  2034         newStr at:i put:c
  2034 	newStr at:i put:c
  2035     ].
  2035     ].
  2036     ^ newStr
  2036     ^ newStr
  2037 
  2037 
  2038     "
  2038     "
  2039      'HelloWorld' asLowercase   
  2039      'HelloWorld' asLowercase
  2040      'HelloWorld' asLowercaseFirst   
  2040      'HelloWorld' asLowercaseFirst
  2041     "
  2041     "
  2042 !
  2042 !
  2043 
  2043 
  2044 asLowercaseFirst
  2044 asLowercaseFirst
  2045     "return a copy of myself where the first character is converted to lowercase."
  2045     "return a copy of myself where the first character is converted to lowercase."
  2049     firstChar := (self at:1).
  2049     firstChar := (self at:1).
  2050     firstCharAsLowercase := firstChar asLowercase.
  2050     firstCharAsLowercase := firstChar asLowercase.
  2051     firstChar == firstCharAsLowercase ifTrue:[ ^ self].
  2051     firstChar == firstCharAsLowercase ifTrue:[ ^ self].
  2052 
  2052 
  2053     firstCharAsLowercase bitsPerCharacter > self bitsPerCharacter ifTrue:[
  2053     firstCharAsLowercase bitsPerCharacter > self bitsPerCharacter ifTrue:[
  2054         newString := firstCharAsLowercase stringSpecies fromString:self.
  2054 	newString := firstCharAsLowercase stringSpecies fromString:self.
  2055     ] ifFalse:[
  2055     ] ifFalse:[
  2056         newString := self stringSpecies fromString:self.
  2056 	newString := self stringSpecies fromString:self.
  2057     ].
  2057     ].
  2058     newString at:1 put:firstCharAsLowercase.
  2058     newString at:1 put:firstCharAsLowercase.
  2059     ^ newString
  2059     ^ newString
  2060 
  2060 
  2061     "
  2061     "
  2062      'HelloWorld' asLowercase   
  2062      'HelloWorld' asLowercase
  2063      'HelloWorld' asLowercaseFirst   
  2063      'HelloWorld' asLowercaseFirst
  2064     "
  2064     "
  2065 !
  2065 !
  2066 
  2066 
  2067 asNumber
  2067 asNumber
  2068     "read a number from the receiver.
  2068     "read a number from the receiver.
  2069      Notice, that (in contrast to ST-80) errors may occur during the read, 
  2069      Notice, that (in contrast to ST-80) errors may occur during the read,
  2070      so you better setup some signal handler when using this method.
  2070      so you better setup some signal handler when using this method.
  2071      This may change if ANSI specifies it."
  2071      This may change if ANSI specifies it."
  2072 
  2072 
  2073 "/ ST-80 behavior:
  2073 "/ ST-80 behavior:
  2074 "/  ^ Number readFromString:self onError:0
  2074 "/  ^ Number readFromString:self onError:0
  2078     "
  2078     "
  2079      '123'     asNumber
  2079      '123'     asNumber
  2080      '123.567' asNumber
  2080      '123.567' asNumber
  2081      '(5/6)'   asNumber
  2081      '(5/6)'   asNumber
  2082      'foo'     asNumber
  2082      'foo'     asNumber
  2083      Object errorSignal handle:[:ex | ex returnWith:0] do:['foo' asNumber] 
  2083      Object errorSignal handle:[:ex | ex returnWith:0] do:['foo' asNumber]
  2084     "
  2084     "
  2085 !
  2085 !
  2086 
  2086 
  2087 asNumberFromFormatString:ignored
  2087 asNumberFromFormatString:ignored
  2088     "read a number from the receiver, ignoring any nonDigit characters.
  2088     "read a number from the receiver, ignoring any nonDigit characters.
  2141 
  2141 
  2142     |newString|
  2142     |newString|
  2143 
  2143 
  2144     newString := String new:(self size).
  2144     newString := String new:(self size).
  2145     1 to:self size do:[:idx |
  2145     1 to:self size do:[:idx |
  2146         |char|
  2146 	|char|
  2147 
  2147 
  2148         char := self at:idx.
  2148 	char := self at:idx.
  2149         char codePoint <= 16rFF ifTrue:[
  2149 	char codePoint <= 16rFF ifTrue:[
  2150             newString at:idx put:char
  2150 	    newString at:idx put:char
  2151         ] ifFalse:[
  2151 	] ifFalse:[
  2152             newString at:idx put:replacementCharacter
  2152 	    newString at:idx put:replacementCharacter
  2153         ].
  2153 	].
  2154     ].
  2154     ].
  2155     ^ newString
  2155     ^ newString
  2156 
  2156 
  2157     "Created: 30.6.1997 / 13:02:14 / cg"
  2157     "Created: 30.6.1997 / 13:02:14 / cg"
  2158 !
  2158 !
  2167     |s d ch last lch n codes sc|
  2167     |s d ch last lch n codes sc|
  2168 
  2168 
  2169     s := self readStream.
  2169     s := self readStream.
  2170     s skipSeparators.
  2170     s skipSeparators.
  2171     s atEnd ifTrue:[
  2171     s atEnd ifTrue:[
  2172         ^ nil
  2172 	^ nil
  2173     ].
  2173     ].
  2174     ch := s next.
  2174     ch := s next.
  2175     ch isLetter ifFalse:[
  2175     ch isLetter ifFalse:[
  2176         ^ nil
  2176 	^ nil
  2177     ].
  2177     ].
  2178     n := 0.
  2178     n := 0.
  2179 
  2179 
  2180     codes := Dictionary new.
  2180     codes := Dictionary new.
  2181     codes atAll:'bpfv'     put:$1.
  2181     codes atAll:'bpfv'     put:$1.
  2184     codes at:$l put:$4.
  2184     codes at:$l put:$4.
  2185     codes atAll:'nm'       put:$5.
  2185     codes atAll:'nm'       put:$5.
  2186     codes at:$r put:$6.
  2186     codes at:$r put:$6.
  2187 
  2187 
  2188     d := String writeStream.
  2188     d := String writeStream.
  2189     d nextPut:(ch asUppercase). 
  2189     d nextPut:(ch asUppercase).
  2190 
  2190 
  2191     [s atEnd] whileFalse:[
  2191     [s atEnd] whileFalse:[
  2192         ch := s next.
  2192 	ch := s next.
  2193         lch := ch asLowercase.
  2193 	lch := ch asLowercase.
  2194         lch = last ifFalse:[
  2194 	lch = last ifFalse:[
  2195             last := lch.
  2195 	    last := lch.
  2196 
  2196 
  2197             sc := codes at:ch ifAbsent:nil.
  2197 	    sc := codes at:ch ifAbsent:nil.
  2198             sc notNil ifTrue:[
  2198 	    sc notNil ifTrue:[
  2199                 n < 3 ifTrue:[
  2199 		n < 3 ifTrue:[
  2200                     d nextPut:sc.
  2200 		    d nextPut:sc.
  2201                     n := n + 1.
  2201 		    n := n + 1.
  2202                 ]
  2202 		]
  2203             ] ifFalse:[
  2203 	    ] ifFalse:[
  2204 "/                ch isLetter ifFalse:[
  2204 "/                ch isLetter ifFalse:[
  2205 "/                    "/ something else - ignore it
  2205 "/                    "/ something else - ignore it
  2206 "/                ] ifTrue:[
  2206 "/                ] ifTrue:[
  2207 "/                    "/ else its a vowel and we ignore it 
  2207 "/                    "/ else its a vowel and we ignore it
  2208 "/                ]
  2208 "/                ]
  2209             ].
  2209 	    ].
  2210         ]
  2210 	]
  2211     ].
  2211     ].
  2212     [ n < 3 ] whileTrue:[
  2212     [ n < 3 ] whileTrue:[
  2213         d nextPut:$0.
  2213 	d nextPut:$0.
  2214         n := n + 1.
  2214 	n := n + 1.
  2215     ].
  2215     ].
  2216 
  2216 
  2217     ^ d contents
  2217     ^ d contents
  2218 
  2218 
  2219     "
  2219     "
  2220      'claus' asSoundexCode    
  2220      'claus' asSoundexCode
  2221      'clause' asSoundexCode   
  2221      'clause' asSoundexCode
  2222      'close' asSoundexCode   
  2222      'close' asSoundexCode
  2223      'smalltalk' asSoundexCode  
  2223      'smalltalk' asSoundexCode
  2224      'smaltalk' asSoundexCode   
  2224      'smaltalk' asSoundexCode
  2225      'smaltak' asSoundexCode    
  2225      'smaltak' asSoundexCode
  2226      'smaltok' asSoundexCode    
  2226      'smaltok' asSoundexCode
  2227      'smoltok' asSoundexCode   
  2227      'smoltok' asSoundexCode
  2228      'aa' asSoundexCode        
  2228      'aa' asSoundexCode
  2229      'by' asSoundexCode        
  2229      'by' asSoundexCode
  2230      'bab' asSoundexCode       
  2230      'bab' asSoundexCode
  2231      'bob' asSoundexCode       
  2231      'bob' asSoundexCode
  2232      'bop' asSoundexCode       
  2232      'bop' asSoundexCode
  2233     "
  2233     "
  2234 !
  2234 !
  2235 
  2235 
  2236 asString
  2236 asString
  2237     "return myself - I am a string"
  2237     "return myself - I am a string"
  2261 
  2261 
  2262 asSymbolIfInterned
  2262 asSymbolIfInterned
  2263     "if a symbol with the receivers characters is already known, return it.
  2263     "if a symbol with the receivers characters is already known, return it.
  2264      Otherwise, return nil. This can be used to query for an existing
  2264      Otherwise, return nil. This can be used to query for an existing
  2265      symbol and is the same as
  2265      symbol and is the same as
  2266         self knownAsSymbol ifTrue:[self asSymbol] ifFalse:[nil]
  2266 	self knownAsSymbol ifTrue:[self asSymbol] ifFalse:[nil]
  2267      but slightly faster, since the symbol lookup operation is only performed once.
  2267      but slightly faster, since the symbol lookup operation is only performed once.
  2268      The receiver must be a singleByte-String.
  2268      The receiver must be a singleByte-String.
  2269      TwoByte- and FourByteSymbols are (currently ?) not allowed."
  2269      TwoByte- and FourByteSymbols are (currently ?) not allowed."
  2270 
  2270 
  2271     |s|
  2271     |s|
  2281 !
  2281 !
  2282 
  2282 
  2283 asText
  2283 asText
  2284     "return a Text-object (collection of lines) from myself."
  2284     "return a Text-object (collection of lines) from myself."
  2285 
  2285 
  2286     "this test allows for small non-gui apps to be built without libbasic2 (where Text is)"    
  2286     "this test allows for small non-gui apps to be built without libbasic2 (where Text is)"
  2287     Text isNil ifTrue:[^ self].
  2287     Text isNil ifTrue:[^ self].
  2288     ^ Text fromString:self
  2288     ^ Text fromString:self
  2289 
  2289 
  2290     "Created: 12.5.1996 / 10:41:14 / cg"
  2290     "Created: 12.5.1996 / 10:41:14 / cg"
  2291 !
  2291 !
  2301     mySize := self size.
  2301     mySize := self size.
  2302     newStr := self species new:mySize.
  2302     newStr := self species new:mySize.
  2303     bitsPerCharacter := newStr bitsPerCharacter.
  2303     bitsPerCharacter := newStr bitsPerCharacter.
  2304 
  2304 
  2305     1 to:mySize do:[:i |
  2305     1 to:mySize do:[:i |
  2306         i == 1 ifTrue:[
  2306 	i == 1 ifTrue:[
  2307             c := (self at:i) asTitlecase.
  2307 	    c := (self at:i) asTitlecase.
  2308         ] ifFalse:[
  2308 	] ifFalse:[
  2309             c := (self at:i) asLowercase.
  2309 	    c := (self at:i) asLowercase.
  2310         ].
  2310 	].
  2311         c bitsPerCharacter > bitsPerCharacter ifTrue:[
  2311 	c bitsPerCharacter > bitsPerCharacter ifTrue:[
  2312             newStr := c stringSpecies fromString:newStr.    
  2312 	    newStr := c stringSpecies fromString:newStr.
  2313         ].
  2313 	].
  2314         newStr at:i put:c
  2314 	newStr at:i put:c
  2315     ].
  2315     ].
  2316     ^ newStr
  2316     ^ newStr
  2317 
  2317 
  2318     "
  2318     "
  2319      'helloWorld' asTitlecase    
  2319      'helloWorld' asTitlecase
  2320      'HelloWorld' asTitlecase   
  2320      'HelloWorld' asTitlecase
  2321      'HELLOWORLD' asTitlecase   
  2321      'HELLOWORLD' asTitlecase
  2322      'helloworld' asTitlecase   
  2322      'helloworld' asTitlecase
  2323     "
  2323     "
  2324 !
  2324 !
  2325 
  2325 
  2326 asTitlecaseFirst
  2326 asTitlecaseFirst
  2327     "return a version of the receiver, where the first character is converted to titlecase.
  2327     "return a version of the receiver, where the first character is converted to titlecase.
  2329      (2-character glyphs), which consist of an upper- and lower-case characters.
  2329      (2-character glyphs), which consist of an upper- and lower-case characters.
  2330      If the first character is already titlecase, or there is no titlecasepercase for it, return the
  2330      If the first character is already titlecase, or there is no titlecasepercase for it, return the
  2331      receiver."
  2331      receiver."
  2332 
  2332 
  2333     "
  2333     "
  2334      For example, in Unicode, character U+01F3 is LATIN SMALL LETTER DZ.  
  2334      For example, in Unicode, character U+01F3 is LATIN SMALL LETTER DZ.
  2335      (Let us write this compound character using ASCII as 'dz'.) 
  2335      (Let us write this compound character using ASCII as 'dz'.)
  2336      This character uppercases to character U+01F1, LATIN CAPITAL LETTER DZ.  
  2336      This character uppercases to character U+01F1, LATIN CAPITAL LETTER DZ.
  2337      (Which is basically 'DZ'.) 
  2337      (Which is basically 'DZ'.)
  2338      But it titlecases to to character U+01F2, LATIN CAPITAL LETTER D WITH SMALL LETTER Z. 
  2338      But it titlecases to to character U+01F2, LATIN CAPITAL LETTER D WITH SMALL LETTER Z.
  2339      (Which we can write 'Dz'.)
  2339      (Which we can write 'Dz'.)
  2340 
  2340 
  2341       character uppercase titlecase
  2341       character uppercase titlecase
  2342       --------- --------- ---------
  2342       --------- --------- ---------
  2343       dz        DZ        Dz
  2343       dz        DZ        Dz
  2348     firstChar := (self at:1).
  2348     firstChar := (self at:1).
  2349     firstCharAsTitlecase := firstChar asTitlecase.
  2349     firstCharAsTitlecase := firstChar asTitlecase.
  2350     firstChar == firstCharAsTitlecase ifTrue:[ ^ self].
  2350     firstChar == firstCharAsTitlecase ifTrue:[ ^ self].
  2351 
  2351 
  2352     firstCharAsTitlecase bitsPerCharacter > self bitsPerCharacter ifTrue:[
  2352     firstCharAsTitlecase bitsPerCharacter > self bitsPerCharacter ifTrue:[
  2353         newString := firstCharAsTitlecase stringSpecies fromString:self.
  2353 	newString := firstCharAsTitlecase stringSpecies fromString:self.
  2354     ] ifFalse:[
  2354     ] ifFalse:[
  2355         newString := self stringSpecies fromString:self.
  2355 	newString := self stringSpecies fromString:self.
  2356     ].
  2356     ].
  2357     newString at:1 put:firstCharAsTitlecase.
  2357     newString at:1 put:firstCharAsTitlecase.
  2358     ^ newString
  2358     ^ newString
  2359 
  2359 
  2360     "
  2360     "
  2361      'helloWorld' asTitlecaseFirst   
  2361      'helloWorld' asTitlecaseFirst
  2362      'HelloWorld' asTitlecaseFirst   
  2362      'HelloWorld' asTitlecaseFirst
  2363     "
  2363     "
  2364 !
  2364 !
  2365 
  2365 
  2366 asTwoByteString
  2366 asTwoByteString
  2367     "return the receiver converted to a two-byte string.
  2367     "return the receiver converted to a two-byte string.
  2371 !
  2371 !
  2372 
  2372 
  2373 asURI
  2373 asURI
  2374     "return an URI with string taken from the receiver"
  2374     "return an URI with string taken from the receiver"
  2375 
  2375 
  2376     ^ URI fromString:self 
  2376     ^ URI fromString:self
  2377 !
  2377 !
  2378 
  2378 
  2379 asURL
  2379 asURL
  2380     "return an URL-object from myself."
  2380     "return an URL-object from myself."
  2381 
  2381 
  2382     ^ URL fromString:self
  2382     ^ URL fromString:self
  2383 
  2383 
  2384     "
  2384     "
  2385      'http://www.exept.de:80/index.html' asURL host    
  2385      'http://www.exept.de:80/index.html' asURL host
  2386      'http://www.exept.de:80/index.html' asURL port    
  2386      'http://www.exept.de:80/index.html' asURL port
  2387      'http://www.exept.de:80/index.html' asURL method    
  2387      'http://www.exept.de:80/index.html' asURL method
  2388      'http://www.exept.de:80/index.html' asURL path    
  2388      'http://www.exept.de:80/index.html' asURL path
  2389     "
  2389     "
  2390 !
  2390 !
  2391 
  2391 
  2392 asUnicode16String
  2392 asUnicode16String
  2393     "thats not really true - characters above ascii 16r7F may need special treatment"
  2393     "thats not really true - characters above ascii 16r7F may need special treatment"
  2416     mySize := self size.
  2416     mySize := self size.
  2417     newStr := self species new:mySize.
  2417     newStr := self species new:mySize.
  2418     bitsPerCharacter := newStr bitsPerCharacter.
  2418     bitsPerCharacter := newStr bitsPerCharacter.
  2419 
  2419 
  2420     1 to:mySize do:[:i |
  2420     1 to:mySize do:[:i |
  2421         c := (self at:i) asUppercase.
  2421 	c := (self at:i) asUppercase.
  2422         c bitsPerCharacter > bitsPerCharacter ifTrue:[
  2422 	c bitsPerCharacter > bitsPerCharacter ifTrue:[
  2423             newStr := c stringSpecies fromString:newStr.    
  2423 	    newStr := c stringSpecies fromString:newStr.
  2424         ].
  2424 	].
  2425         newStr at:i put:c
  2425 	newStr at:i put:c
  2426     ].
  2426     ].
  2427     ^ newStr
  2427     ^ newStr
  2428 
  2428 
  2429     "
  2429     "
  2430      'helloWorld' asUppercase      
  2430      'helloWorld' asUppercase
  2431      'helloWorld' asUppercaseFirst 
  2431      'helloWorld' asUppercaseFirst
  2432      (Character value:16rB5) asString asUppercase   -- needs 16 bits !!
  2432      (Character value:16rB5) asString asUppercase   -- needs 16 bits !!
  2433     "
  2433     "
  2434 !
  2434 !
  2435 
  2435 
  2436 asUppercaseFirst
  2436 asUppercaseFirst
  2443     firstChar := (self at:1).
  2443     firstChar := (self at:1).
  2444     firstCharAsUppercase := firstChar asUppercase.
  2444     firstCharAsUppercase := firstChar asUppercase.
  2445     firstChar == firstCharAsUppercase ifTrue:[ ^ self].
  2445     firstChar == firstCharAsUppercase ifTrue:[ ^ self].
  2446 
  2446 
  2447     firstCharAsUppercase bitsPerCharacter > self bitsPerCharacter ifTrue:[
  2447     firstCharAsUppercase bitsPerCharacter > self bitsPerCharacter ifTrue:[
  2448         newString := firstCharAsUppercase stringSpecies fromString:self.
  2448 	newString := firstCharAsUppercase stringSpecies fromString:self.
  2449     ] ifFalse:[
  2449     ] ifFalse:[
  2450         newString := self stringSpecies fromString:self.
  2450 	newString := self stringSpecies fromString:self.
  2451     ].
  2451     ].
  2452     newString at:1 put:firstCharAsUppercase.
  2452     newString at:1 put:firstCharAsUppercase.
  2453     ^ newString
  2453     ^ newString
  2454 
  2454 
  2455     "
  2455     "
  2456      'helloWorld' asUppercase      
  2456      'helloWorld' asUppercase
  2457      'helloWorld' asUppercaseFirst 
  2457      'helloWorld' asUppercaseFirst
  2458      'HelloWorld' asUppercaseFirst   
  2458      'HelloWorld' asUppercaseFirst
  2459     "
  2459     "
  2460 !
  2460 !
  2461 
  2461 
  2462 string
  2462 string
  2463     "return the receiver - for ST-80 compatibility"
  2463     "return the receiver - for ST-80 compatibility"
  2487      This is nonStandard, but convenient"
  2487      This is nonStandard, but convenient"
  2488 
  2488 
  2489     |myWidth otherWidth|
  2489     |myWidth otherWidth|
  2490 
  2490 
  2491     aStringOrCharacter isCharacter ifTrue:[
  2491     aStringOrCharacter isCharacter ifTrue:[
  2492         ^ self copyWith:aStringOrCharacter
  2492 	^ self copyWith:aStringOrCharacter
  2493     ].
  2493     ].
  2494     aStringOrCharacter isText ifTrue:[
  2494     aStringOrCharacter isText ifTrue:[
  2495         ^ aStringOrCharacter concatenateFromString:self
  2495 	^ aStringOrCharacter concatenateFromString:self
  2496     ].
  2496     ].
  2497     aStringOrCharacter isString ifTrue:[
  2497     aStringOrCharacter isString ifTrue:[
  2498         (otherWidth := aStringOrCharacter bitsPerCharacter) ~~ (myWidth := self bitsPerCharacter) ifTrue:[
  2498 	(otherWidth := aStringOrCharacter bitsPerCharacter) ~~ (myWidth := self bitsPerCharacter) ifTrue:[
  2499             otherWidth > myWidth ifTrue:[
  2499 	    otherWidth > myWidth ifTrue:[
  2500                 ^ (aStringOrCharacter species fromString:self) , aStringOrCharacter
  2500 		^ (aStringOrCharacter species fromString:self) , aStringOrCharacter
  2501             ].
  2501 	    ].
  2502             ^ self , (self species fromString:aStringOrCharacter)
  2502 	    ^ self , (self species fromString:aStringOrCharacter)
  2503         ].
  2503 	].
  2504     ].
  2504     ].
  2505     ^ super , aStringOrCharacter
  2505     ^ super , aStringOrCharacter
  2506 
  2506 
  2507     "
  2507     "
  2508      'hello' , $1    
  2508      'hello' , $1
  2509      'hello' , '1'   
  2509      'hello' , '1'
  2510      'hello' , (' world' asText allBold) 
  2510      'hello' , (' world' asText allBold)
  2511      'hello' , (JISEncodedString fromString:' world') 
  2511      'hello' , (JISEncodedString fromString:' world')
  2512      (JISEncodedString fromString:'hello') , ' world'
  2512      (JISEncodedString fromString:'hello') , ' world'
  2513 
  2513 
  2514      Transcript showCR:
  2514      Transcript showCR:
  2515          (Text string:'hello' emphasis:#italic) , (Text string:' world' emphasis:#bold) 
  2515 	 (Text string:'hello' emphasis:#italic) , (Text string:' world' emphasis:#bold)
  2516     "
  2516     "
  2517 
  2517 
  2518     "Modified: 28.6.1997 / 00:13:17 / cg"
  2518     "Modified: 28.6.1997 / 00:13:17 / cg"
  2519 !
  2519 !
  2520 
  2520 
  2554     |tmpStream idx idx1|
  2554     |tmpStream idx idx1|
  2555 
  2555 
  2556     tmpStream := WriteStream on:(self class new).
  2556     tmpStream := WriteStream on:(self class new).
  2557     idx := 1.
  2557     idx := 1.
  2558     [idx ~~ 0] whileTrue:[
  2558     [idx ~~ 0] whileTrue:[
  2559         idx1 := idx.
  2559 	idx1 := idx.
  2560         idx := self indexOfSubCollection:subString startingAt:idx.
  2560 	idx := self indexOfSubCollection:subString startingAt:idx.
  2561         idx ~~ 0 ifTrue:[
  2561 	idx ~~ 0 ifTrue:[
  2562             tmpStream nextPutAll:(self copyFrom:idx1 to:idx-1).
  2562 	    tmpStream nextPutAll:(self copyFrom:idx1 to:idx-1).
  2563             tmpStream nextPutAll:newString.
  2563 	    tmpStream nextPutAll:newString.
  2564             idx := idx + subString size
  2564 	    idx := idx + subString size
  2565         ]
  2565 	]
  2566     ].
  2566     ].
  2567     tmpStream nextPutAll:(self copyFrom:idx1).
  2567     tmpStream nextPutAll:(self copyFrom:idx1).
  2568     ^ tmpStream contents
  2568     ^ tmpStream contents
  2569 
  2569 
  2570    "
  2570    "
  2571      '12345678901234567890' replString:'123' withString:'OneTwoThree' 
  2571      '12345678901234567890' replString:'123' withString:'OneTwoThree'
  2572      '12345678901234567890' replString:'123' withString:'*' 
  2572      '12345678901234567890' replString:'123' withString:'*'
  2573      '12345678901234567890' replString:'234' withString:'foo' 
  2573      '12345678901234567890' replString:'234' withString:'foo'
  2574 
  2574 
  2575      ('a string with spaces' replChar:$  withString:' foo ')
  2575      ('a string with spaces' replChar:$  withString:' foo ')
  2576         replString:'foo' withString:'bar'
  2576 	replString:'foo' withString:'bar'
  2577     "
  2577     "
  2578 
  2578 
  2579     "Modified: / 31-05-1999 / 12:33:59 / cg"
  2579     "Modified: / 31-05-1999 / 12:33:59 / cg"
  2580     "Created: / 12-05-2004 / 12:00:00 / cg"
  2580     "Created: / 12-05-2004 / 12:00:00 / cg"
  2581 !
  2581 !
  2582 
  2582 
  2583 copyWith:aCharacter
  2583 copyWith:aCharacter
  2584     "return a new string containing the receivers characters
  2584     "return a new string containing the receivers characters
  2585      and the single new character, aCharacter. 
  2585      and the single new character, aCharacter.
  2586      This is different from concatentation, which expects another string
  2586      This is different from concatentation, which expects another string
  2587      as argument, but equivalent to copy-and-addLast.
  2587      as argument, but equivalent to copy-and-addLast.
  2588      The code below cares for different width characters 
  2588      The code below cares for different width characters
  2589      (i.e. when appending a 16bit char to an 8bit string)"
  2589      (i.e. when appending a 16bit char to an 8bit string)"
  2590 
  2590 
  2591     |sz newString|
  2591     |sz newString|
  2592 
  2592 
  2593     aCharacter bitsPerCharacter > self bitsPerCharacter ifTrue:[
  2593     aCharacter bitsPerCharacter > self bitsPerCharacter ifTrue:[
  2594         sz := self size.
  2594 	sz := self size.
  2595         newString := aCharacter stringSpecies new:sz + 1.
  2595 	newString := aCharacter stringSpecies new:sz + 1.
  2596         newString replaceFrom:1 to:sz with:self startingAt:1.
  2596 	newString replaceFrom:1 to:sz with:self startingAt:1.
  2597         newString at:sz+1 put:aCharacter.
  2597 	newString at:sz+1 put:aCharacter.
  2598         ^ newString.
  2598 	^ newString.
  2599     ].
  2599     ].
  2600     ^ super copyWith:aCharacter
  2600     ^ super copyWith:aCharacter
  2601 ! !
  2601 ! !
  2602 
  2602 
  2603 !CharacterArray methodsFor:'displaying'!
  2603 !CharacterArray methodsFor:'displaying'!
  2618 
  2618 
  2619     |s|
  2619     |s|
  2620 
  2620 
  2621     s := self string.
  2621     s := self string.
  2622     opaque ifTrue:[
  2622     opaque ifTrue:[
  2623         aGc displayOpaqueString:s x:x y:y.
  2623 	aGc displayOpaqueString:s x:x y:y.
  2624     ] ifFalse:[
  2624     ] ifFalse:[
  2625         aGc displayString:s x:x y:y.
  2625 	aGc displayString:s x:x y:y.
  2626     ].
  2626     ].
  2627 
  2627 
  2628     "Modified: 11.5.1996 / 14:42:48 / cg"
  2628     "Modified: 11.5.1996 / 14:42:48 / cg"
  2629 !
  2629 !
  2630 
  2630 
  2642 !CharacterArray methodsFor:'emphasis'!
  2642 !CharacterArray methodsFor:'emphasis'!
  2643 
  2643 
  2644 allBold
  2644 allBold
  2645     "return a test object representing the receiver, but all boldified"
  2645     "return a test object representing the receiver, but all boldified"
  2646 
  2646 
  2647     "this test allows for small non-gui apps to be built without libbasic2 (where Text is)"    
  2647     "this test allows for small non-gui apps to be built without libbasic2 (where Text is)"
  2648     Text isNil ifTrue:[^ self].
  2648     Text isNil ifTrue:[^ self].
  2649     ^ self asText allBold
  2649     ^ self asText allBold
  2650 
  2650 
  2651     "
  2651     "
  2652      Transcript showCR:'hello' asText allBold
  2652      Transcript showCR:'hello' asText allBold
  2655 !
  2655 !
  2656 
  2656 
  2657 allItalic
  2657 allItalic
  2658     "return a test object representing the receiver, but all in italic"
  2658     "return a test object representing the receiver, but all in italic"
  2659 
  2659 
  2660     "this test allows for small non-gui apps to be built without libbasic2 (where Text is)"    
  2660     "this test allows for small non-gui apps to be built without libbasic2 (where Text is)"
  2661     Text isNil ifTrue:[^ self].
  2661     Text isNil ifTrue:[^ self].
  2662     ^ self asText allItalic
  2662     ^ self asText allItalic
  2663 
  2663 
  2664     "
  2664     "
  2665      Transcript showCR:'hello' asText allItalic
  2665      Transcript showCR:'hello' asText allItalic
  2745 ! !
  2745 ! !
  2746 
  2746 
  2747 !CharacterArray methodsFor:'encoding & decoding'!
  2747 !CharacterArray methodsFor:'encoding & decoding'!
  2748 
  2748 
  2749 decodeFrom:encodingSymbol
  2749 decodeFrom:encodingSymbol
  2750     "given the receiver encoded as described by encodingSymbol, 
  2750     "given the receiver encoded as described by encodingSymbol,
  2751      convert it into internal ST/X (unicode) encoding and return a corresponding CharacterArray."
  2751      convert it into internal ST/X (unicode) encoding and return a corresponding CharacterArray."
  2752 
  2752 
  2753     |myEncoding encoder|
  2753     |myEncoding encoder|
  2754 
  2754 
  2755     encodingSymbol isNil ifTrue:[^ self].
  2755     encodingSymbol isNil ifTrue:[^ self].
  2764 encodeFrom:oldEncoding into:newEncoding
  2764 encodeFrom:oldEncoding into:newEncoding
  2765     ^ CharacterEncoder encodeString:self from:oldEncoding into:newEncoding
  2765     ^ CharacterEncoder encodeString:self from:oldEncoding into:newEncoding
  2766 !
  2766 !
  2767 
  2767 
  2768 rot13
  2768 rot13
  2769      "Usenet: from `rotate alphabet 13 places'] 
  2769      "Usenet: from `rotate alphabet 13 places']
  2770       The simple Caesar-cypher encryption that replaces each English
  2770       The simple Caesar-cypher encryption that replaces each English
  2771       letter with the one 13 places forward or back along the alphabet, 
  2771       letter with the one 13 places forward or back along the alphabet,
  2772       so that 'The butler did it!!' becomes 'Gur ohgyre qvq vg!!'
  2772       so that 'The butler did it!!' becomes 'Gur ohgyre qvq vg!!'
  2773       Most Usenet news reading and posting programs include a rot13 feature. 
  2773       Most Usenet news reading and posting programs include a rot13 feature.
  2774       It is used to enclose the text in a sealed wrapper that the reader must choose
  2774       It is used to enclose the text in a sealed wrapper that the reader must choose
  2775       to open -- e.g., for posting things that might offend some readers, or spoilers. 
  2775       to open -- e.g., for posting things that might offend some readers, or spoilers.
  2776       A major advantage of rot13 over rot(N) for other N is that it
  2776       A major advantage of rot13 over rot(N) for other N is that it
  2777       is self-inverse, so the same code can be used for encoding and decoding."
  2777       is self-inverse, so the same code can be used for encoding and decoding."
  2778 
  2778 
  2779     ^ self species 
  2779     ^ self species
  2780         streamContents:[:aStream | 
  2780 	streamContents:[:aStream |
  2781             self do:[:char | 
  2781 	    self do:[:char |
  2782                 aStream nextPut:char rot13 ]]
  2782 		aStream nextPut:char rot13 ]]
  2783 
  2783 
  2784     "
  2784     "
  2785      'hello world' rot13    
  2785      'hello world' rot13
  2786      'hello world' rot13 rot13   
  2786      'hello world' rot13 rot13
  2787     "
  2787     "
  2788 !
  2788 !
  2789 
  2789 
  2790 utf8Decoded
  2790 utf8Decoded
  2791     "Interpreting myself as an UTF-8 representation, decode and return the decoded string."
  2791     "Interpreting myself as an UTF-8 representation, decode and return the decoded string."
  2794 
  2794 
  2795     is16Bit := false.
  2795     is16Bit := false.
  2796     out := WriteStream on:(String uninitializedNew:self size).
  2796     out := WriteStream on:(String uninitializedNew:self size).
  2797     in := self readStream.
  2797     in := self readStream.
  2798     [in atEnd] whileFalse:[
  2798     [in atEnd] whileFalse:[
  2799         c := Character utf8DecodeFrom:in.
  2799 	c := Character utf8DecodeFrom:in.
  2800         is16Bit ifFalse:[
  2800 	is16Bit ifFalse:[
  2801             c codePoint > 16rFF ifTrue:[
  2801 	    c codePoint > 16rFF ifTrue:[
  2802                 out := WriteStream with:(UnicodeString fromString:out contents).
  2802 		out := WriteStream with:(UnicodeString fromString:out contents).
  2803                 is16Bit := true.
  2803 		is16Bit := true.
  2804             ].
  2804 	    ].
  2805         ].
  2805 	].
  2806         out nextPut:c.
  2806 	out nextPut:c.
  2807     ].        
  2807     ].
  2808     ^ out contents
  2808     ^ out contents
  2809 
  2809 
  2810     "
  2810     "
  2811      #[16rC8 16rA0] asString utf8Decoded 
  2811      #[16rC8 16rA0] asString utf8Decoded
  2812      (Character value:16r220) utf8Encoded   
  2812      (Character value:16r220) utf8Encoded
  2813      (Character value:16r220) utf8Encoded utf8Decoded  
  2813      (Character value:16r220) utf8Encoded utf8Decoded
  2814 
  2814 
  2815      (Character value:16r800) utf8Encoded      
  2815      (Character value:16r800) utf8Encoded
  2816      (Character value:16r220) utf8Encoded utf8Decoded  
  2816      (Character value:16r220) utf8Encoded utf8Decoded
  2817     "
  2817     "
  2818 
  2818 
  2819     "test:
  2819     "test:
  2820 
  2820 
  2821       |utf8Encoding original readBack|
  2821       |utf8Encoding original readBack|
  2822 
  2822 
  2823       1 to:16rFFFF do:[:ascii |
  2823       1 to:16rFFFF do:[:ascii |
  2824         original := (Character value:ascii) asString.
  2824 	original := (Character value:ascii) asString.
  2825         utf8Encoding := original utf8Encoded.
  2825 	utf8Encoding := original utf8Encoded.
  2826         readBack := utf8Encoding utf8Decoded.
  2826 	readBack := utf8Encoding utf8Decoded.
  2827         readBack = original ifFalse:[
  2827 	readBack = original ifFalse:[
  2828             self halt
  2828 	    self halt
  2829         ]
  2829 	]
  2830       ]
  2830       ]
  2831     "
  2831     "
  2832 !
  2832 !
  2833 
  2833 
  2834 utf8DecodedWithTwoByteCharactersReplacedBy:replacementCharacter
  2834 utf8DecodedWithTwoByteCharactersReplacedBy:replacementCharacter
  2839     |in out c|
  2839     |in out c|
  2840 
  2840 
  2841     out := WriteStream on:(String uninitializedNew:self size).
  2841     out := WriteStream on:(String uninitializedNew:self size).
  2842     in := self readStream.
  2842     in := self readStream.
  2843     [in atEnd] whileFalse:[
  2843     [in atEnd] whileFalse:[
  2844         c := Character utf8DecodeFrom:in.
  2844 	c := Character utf8DecodeFrom:in.
  2845         c codePoint > 16rFF ifTrue:[
  2845 	c codePoint > 16rFF ifTrue:[
  2846             c := replacementCharacter
  2846 	    c := replacementCharacter
  2847         ].
  2847 	].
  2848         out nextPut:c.
  2848 	out nextPut:c.
  2849     ].        
  2849     ].
  2850     ^ out contents
  2850     ^ out contents
  2851 
  2851 
  2852     "
  2852     "
  2853      (Character value:16r220) utf8Encoded 
  2853      (Character value:16r220) utf8Encoded
  2854         utf8DecodedWithTwoByteCharactersReplacedBy:(Character space)  
  2854 	utf8DecodedWithTwoByteCharactersReplacedBy:(Character space)
  2855     "
  2855     "
  2856 !
  2856 !
  2857 
  2857 
  2858 utf8Encoded
  2858 utf8Encoded
  2859     "Return my UTF-8 representation as a new String"
  2859     "Return my UTF-8 representation as a new String"
  2868 utf8EncodedOn:aStream
  2868 utf8EncodedOn:aStream
  2869     "append my UTF-8 representation to the argument, aStream."
  2869     "append my UTF-8 representation to the argument, aStream."
  2870 
  2870 
  2871 
  2871 
  2872     self do:[:c|
  2872     self do:[:c|
  2873         c utf8EncodedOn:aStream.
  2873 	c utf8EncodedOn:aStream.
  2874     ].
  2874     ].
  2875 ! !
  2875 ! !
  2876 
  2876 
  2877 !CharacterArray methodsFor:'padded copying'!
  2877 !CharacterArray methodsFor:'padded copying'!
  2878 
  2878 
  2879 centerPaddedTo:newSize
  2879 centerPaddedTo:newSize
  2880      "return a new string consisting of the receivers characters,
  2880      "return a new string consisting of the receivers characters,
  2881      plus spaces up to length and center the receivers characters in
  2881      plus spaces up to length and center the receivers characters in
  2882      the resulting string.
  2882      the resulting string.
  2883      If the receivers size is equal or greater than the length argument, 
  2883      If the receivers size is equal or greater than the length argument,
  2884      the original receiver is returned unchanged."
  2884      the original receiver is returned unchanged."
  2885 
  2885 
  2886      ^ self centerPaddedTo:newSize with:(Character space)
  2886      ^ self centerPaddedTo:newSize with:(Character space)
  2887 
  2887 
  2888     "
  2888     "
  2889      'foo' centerPaddedTo:10            
  2889      'foo' centerPaddedTo:10
  2890      123 printString centerPaddedTo:10 
  2890      123 printString centerPaddedTo:10
  2891     "
  2891     "
  2892 
  2892 
  2893     "Created: 25.11.1995 / 10:53:57 / cg"
  2893     "Created: 25.11.1995 / 10:53:57 / cg"
  2894 !
  2894 !
  2895 
  2895 
  2896 centerPaddedTo:size with:padCharacter
  2896 centerPaddedTo:size with:padCharacter
  2897     "return a new string of length size, which contains the receiver
  2897     "return a new string of length size, which contains the receiver
  2898      centered (i.e. padded on both sides).
  2898      centered (i.e. padded on both sides).
  2899      Characters are filled with padCharacter.
  2899      Characters are filled with padCharacter.
  2900      If the receivers size is equal or greater than the length argument, 
  2900      If the receivers size is equal or greater than the length argument,
  2901      the original receiver is returned unchanged."
  2901      the original receiver is returned unchanged."
  2902 
  2902 
  2903     |len s|
  2903     |len s|
  2904 
  2904 
  2905     len := self size.
  2905     len := self size.
  2908 	s replaceFrom:(size - len) // 2  + 1 with:self.
  2908 	s replaceFrom:(size - len) // 2  + 1 with:self.
  2909 	^ s
  2909 	^ s
  2910     ]
  2910     ]
  2911 
  2911 
  2912     "
  2912     "
  2913      'foo' centerPaddedTo:11 with:$.     
  2913      'foo' centerPaddedTo:11 with:$.
  2914      'fooBar' centerPaddedTo:5 with:$.      
  2914      'fooBar' centerPaddedTo:5 with:$.
  2915      123 printString centerPaddedTo:10 with:$.        
  2915      123 printString centerPaddedTo:10 with:$.
  2916      (' ' , 123 printString) centerPaddedTo:10 with:$.        
  2916      (' ' , 123 printString) centerPaddedTo:10 with:$.
  2917      (Float pi printString) centerPaddedTo:15 with:(Character space)  
  2917      (Float pi printString) centerPaddedTo:15 with:(Character space)
  2918      (Float pi printString) centerPaddedTo:15 with:$-           
  2918      (Float pi printString) centerPaddedTo:15 with:$-
  2919      (' ' , Float pi class name) centerPaddedTo:15 with:$.     
  2919      (' ' , Float pi class name) centerPaddedTo:15 with:$.
  2920     "
  2920     "
  2921 !
  2921 !
  2922 
  2922 
  2923 decimalPaddedTo:size and:afterPeriod at:decimalCharacter
  2923 decimalPaddedTo:size and:afterPeriod at:decimalCharacter
  2924     "return a new string of overall length size, which contains the receiver
  2924     "return a new string of overall length size, which contains the receiver
  2925      aligned at the decimal-period column and afterPeriod characters to the right
  2925      aligned at the decimal-period column and afterPeriod characters to the right
  2926      of the period. The periodCharacter is passed as arguments (allowing for US and European formats
  2926      of the period. The periodCharacter is passed as arguments (allowing for US and European formats
  2927      to be padded).
  2927      to be padded).
  2928      If the receivers size is equal or greater than the length argument, 
  2928      If the receivers size is equal or greater than the length argument,
  2929      the original receiver is returned unchanged.
  2929      the original receiver is returned unchanged.
  2930      (sounds complicated ? -> see examples below)."
  2930      (sounds complicated ? -> see examples below)."
  2931 
  2931 
  2932     ^ self 
  2932     ^ self
  2933 	decimalPaddedTo:size 
  2933 	decimalPaddedTo:size
  2934 	and:afterPeriod 
  2934 	and:afterPeriod
  2935 	at:decimalCharacter
  2935 	at:decimalCharacter
  2936 	withLeft:(Character space)
  2936 	withLeft:(Character space)
  2937 	right:$0
  2937 	right:$0
  2938 
  2938 
  2939     "                                                    
  2939     "
  2940      '123' decimalPaddedTo:10 and:3 at:$.      -> '   123    '  
  2940      '123' decimalPaddedTo:10 and:3 at:$.      -> '   123    '
  2941      '123' decimalPaddedTo:10 and:3 at:$.      -> '   123.000'  
  2941      '123' decimalPaddedTo:10 and:3 at:$.      -> '   123.000'
  2942      '123.' decimalPaddedTo:10 and:3 at:$.     -> '   123.000' 
  2942      '123.' decimalPaddedTo:10 and:3 at:$.     -> '   123.000'
  2943      '123.1' decimalPaddedTo:10 and:3 at:$.    -> '   123.100'
  2943      '123.1' decimalPaddedTo:10 and:3 at:$.    -> '   123.100'
  2944      '123.1' decimalPaddedTo:10 and:3 at:$.    -> '   123.1  ' 
  2944      '123.1' decimalPaddedTo:10 and:3 at:$.    -> '   123.1  '
  2945      '123.123' decimalPaddedTo:10 and:3 at:$.  -> '   123.123'
  2945      '123.123' decimalPaddedTo:10 and:3 at:$.  -> '   123.123'
  2946     "
  2946     "
  2947 
  2947 
  2948     "Created: 23.12.1995 / 13:11:52 / cg"
  2948     "Created: 23.12.1995 / 13:11:52 / cg"
  2949 !
  2949 !
  2953      aligned at the decimal-period column and afterPeriod characters to the right
  2953      aligned at the decimal-period column and afterPeriod characters to the right
  2954      of the period.
  2954      of the period.
  2955      Characters on the left are filled with leftPadChar.
  2955      Characters on the left are filled with leftPadChar.
  2956      If rightPadChar is nil, characters on the right are filled with leftPadCharacter too;
  2956      If rightPadChar is nil, characters on the right are filled with leftPadCharacter too;
  2957      otherwise, if missing, a decimal point is added and right characters filled with this.
  2957      otherwise, if missing, a decimal point is added and right characters filled with this.
  2958      If the receivers size is equal or greater than the length argument, 
  2958      If the receivers size is equal or greater than the length argument,
  2959      the original receiver is returned unchanged.
  2959      the original receiver is returned unchanged.
  2960      (sounds complicated ? -> see examples below)."
  2960      (sounds complicated ? -> see examples below)."
  2961 
  2961 
  2962     |s idx n rest|
  2962     |s idx n rest|
  2963 
  2963 
  2964     idx := self indexOf:decimalCharacter.
  2964     idx := self indexOf:decimalCharacter.
  2965     idx == 0 ifTrue:[
  2965     idx == 0 ifTrue:[
  2966         "/
  2966 	"/
  2967         "/ no decimal point found; adjust string to the left of the period column
  2967 	"/ no decimal point found; adjust string to the left of the period column
  2968         "/
  2968 	"/
  2969         rightPadChar isNil ifTrue:[
  2969 	rightPadChar isNil ifTrue:[
  2970             s := self , (self species new:afterPeriod + 1 withAll:leftPadChar)
  2970 	    s := self , (self species new:afterPeriod + 1 withAll:leftPadChar)
  2971         ] ifFalse:[
  2971 	] ifFalse:[
  2972             s:= self , decimalCharacter asString , (self species new:afterPeriod withAll:rightPadChar).
  2972 	    s:= self , decimalCharacter asString , (self species new:afterPeriod withAll:rightPadChar).
  2973         ].
  2973 	].
  2974     ] ifFalse:[
  2974     ] ifFalse:[
  2975 
  2975 
  2976         "/ the number of after-decimalPoint characters
  2976 	"/ the number of after-decimalPoint characters
  2977         n := self size - idx.
  2977 	n := self size - idx.
  2978         rest := afterPeriod - n.
  2978 	rest := afterPeriod - n.
  2979         rest > 0 ifTrue:[
  2979 	rest > 0 ifTrue:[
  2980             s := (self species new:rest withAll:(rightPadChar ? leftPadChar)).
  2980 	    s := (self species new:rest withAll:(rightPadChar ? leftPadChar)).
  2981         ] ifFalse:[
  2981 	] ifFalse:[
  2982             s := ''
  2982 	    s := ''
  2983         ].
  2983 	].
  2984         s := self , s.
  2984 	s := self , s.
  2985     ].
  2985     ].
  2986 
  2986 
  2987     ^ s leftPaddedTo:size with:leftPadChar
  2987     ^ s leftPaddedTo:size with:leftPadChar
  2988 
  2988 
  2989     "                                                    
  2989     "
  2990      '123' decimalPaddedTo:10 and:3 at:$. withLeft:(Character space) right:nil     -> '   123    '  
  2990      '123' decimalPaddedTo:10 and:3 at:$. withLeft:(Character space) right:nil     -> '   123    '
  2991      '123' decimalPaddedTo:10 and:3 at:$. withLeft:(Character space) right:$0      -> '   123.000'  
  2991      '123' decimalPaddedTo:10 and:3 at:$. withLeft:(Character space) right:$0      -> '   123.000'
  2992      '123.' decimalPaddedTo:10 and:3 at:$. withLeft:(Character space) right:$0     -> '   123.000' 
  2992      '123.' decimalPaddedTo:10 and:3 at:$. withLeft:(Character space) right:$0     -> '   123.000'
  2993      '123.1' decimalPaddedTo:10 and:3 at:$. withLeft:(Character space) right:$0    -> '   123.100'
  2993      '123.1' decimalPaddedTo:10 and:3 at:$. withLeft:(Character space) right:$0    -> '   123.100'
  2994      '123.1' decimalPaddedTo:10 and:3 at:$. withLeft:(Character space) right:nil   -> '   123.1  ' 
  2994      '123.1' decimalPaddedTo:10 and:3 at:$. withLeft:(Character space) right:nil   -> '   123.1  '
  2995      '123.123' decimalPaddedTo:10 and:3 at:$. withLeft:(Character space) right:$0  -> '   123.123'
  2995      '123.123' decimalPaddedTo:10 and:3 at:$. withLeft:(Character space) right:$0  -> '   123.123'
  2996     "
  2996     "
  2997 
  2997 
  2998     "Modified: 23.12.1995 / 13:08:18 / cg"
  2998     "Modified: 23.12.1995 / 13:08:18 / cg"
  2999 !
  2999 !
  3000 
  3000 
  3001 leftPaddedTo:size
  3001 leftPaddedTo:size
  3002     "return a new string of length size, which contains the receiver
  3002     "return a new string of length size, which contains the receiver
  3003      right-adjusted (i.e. padded on the left).
  3003      right-adjusted (i.e. padded on the left).
  3004      Characters on the left are filled with spaces.
  3004      Characters on the left are filled with spaces.
  3005      If the receivers size is equal or greater than the length argument, 
  3005      If the receivers size is equal or greater than the length argument,
  3006      the original receiver is returned unchanged."
  3006      the original receiver is returned unchanged."
  3007 
  3007 
  3008     ^ self leftPaddedTo:size with:(Character space)
  3008     ^ self leftPaddedTo:size with:(Character space)
  3009 
  3009 
  3010     "
  3010     "
  3011      'foo' leftPaddedTo:10  
  3011      'foo' leftPaddedTo:10
  3012      'fooBar' leftPaddedTo:5      
  3012      'fooBar' leftPaddedTo:5
  3013      123 printString leftPaddedTo:10        
  3013      123 printString leftPaddedTo:10
  3014     "
  3014     "
  3015 !
  3015 !
  3016 
  3016 
  3017 paddedTo:newSize
  3017 paddedTo:newSize
  3018      "return a new string consisting of the receivers characters,
  3018      "return a new string consisting of the receivers characters,
  3019      plus spaces up to length.
  3019      plus spaces up to length.
  3020      If the receivers size is equal or greater than the length argument, 
  3020      If the receivers size is equal or greater than the length argument,
  3021      the original receiver is returned unchanged."
  3021      the original receiver is returned unchanged."
  3022 
  3022 
  3023      ^ self paddedTo:newSize with:(Character space)
  3023      ^ self paddedTo:newSize with:(Character space)
  3024 
  3024 
  3025     "
  3025     "
  3026      'foo' paddedTo:10            
  3026      'foo' paddedTo:10
  3027      123 printString paddedTo:10 
  3027      123 printString paddedTo:10
  3028     "
  3028     "
  3029 ! !
  3029 ! !
  3030 
  3030 
  3031 !CharacterArray methodsFor:'pattern matching'!
  3031 !CharacterArray methodsFor:'pattern matching'!
  3032 
  3032 
  3036      This is usable with fileName pattern fields."
  3036      This is usable with fileName pattern fields."
  3037 
  3037 
  3038     ^self compoundMatch:aString ignoreCase:false
  3038     ^self compoundMatch:aString ignoreCase:false
  3039 
  3039 
  3040     "
  3040     "
  3041      'f*' match:'foo'       
  3041      'f*' match:'foo'
  3042      'b*' match:'foo'       
  3042      'b*' match:'foo'
  3043      'f*;b*' match:'foo'    
  3043      'f*;b*' match:'foo'
  3044      'f*;b*' match:'bar'    
  3044      'f*;b*' match:'bar'
  3045      'f*;b*' compoundMatch:'foo' 
  3045      'f*;b*' compoundMatch:'foo'
  3046      'f*;b*' compoundMatch:'bar' 
  3046      'f*;b*' compoundMatch:'bar'
  3047     "
  3047     "
  3048 
  3048 
  3049     "Modified: / 30.1.1998 / 11:40:18 / stefan"
  3049     "Modified: / 30.1.1998 / 11:40:18 / stefan"
  3050     "Modified: / 16.12.1999 / 01:22:08 / cg"
  3050     "Modified: / 16.12.1999 / 01:22:08 / cg"
  3051 !
  3051 !
  3057 
  3057 
  3058     |matchers|
  3058     |matchers|
  3059 
  3059 
  3060     matchers := self asCollectionOfSubstringsSeparatedBy:$;.
  3060     matchers := self asCollectionOfSubstringsSeparatedBy:$;.
  3061     matchers do:[:aPattern |
  3061     matchers do:[:aPattern |
  3062         (aPattern match:aString ignoreCase:ignoreCase) ifTrue:[^ true].
  3062 	(aPattern match:aString ignoreCase:ignoreCase) ifTrue:[^ true].
  3063     ].
  3063     ].
  3064     ^ false.
  3064     ^ false.
  3065 
  3065 
  3066     "
  3066     "
  3067      'f*' match:'foo'       
  3067      'f*' match:'foo'
  3068      'b*' match:'foo'       
  3068      'b*' match:'foo'
  3069      'f*;b*' match:'foo'    
  3069      'f*;b*' match:'foo'
  3070      'f*;b*' match:'bar'    
  3070      'f*;b*' match:'bar'
  3071      'f*;b*' compoundMatch:'foo' 
  3071      'f*;b*' compoundMatch:'foo'
  3072      'f*;b*' compoundMatch:'bar' 
  3072      'f*;b*' compoundMatch:'bar'
  3073      'f*;b*' compoundMatch:'Foo' ignoreCase:true 
  3073      'f*;b*' compoundMatch:'Foo' ignoreCase:true
  3074     "
  3074     "
  3075 
  3075 
  3076     "Modified: / 15.4.1997 / 15:50:33 / cg"
  3076     "Modified: / 15.4.1997 / 15:50:33 / cg"
  3077     "Modified: / 30.1.1998 / 11:40:18 / stefan"
  3077     "Modified: / 30.1.1998 / 11:40:18 / stefan"
  3078     "Created: / 16.12.1999 / 01:21:35 / cg"
  3078     "Created: / 16.12.1999 / 01:21:35 / cg"
  3081 findMatchString:matchString
  3081 findMatchString:matchString
  3082     "like findString/indexOfSubCollection, but allowing match patterns.
  3082     "like findString/indexOfSubCollection, but allowing match patterns.
  3083      find matchstring; if found, return the index;
  3083      find matchstring; if found, return the index;
  3084      if not found, return 0."
  3084      if not found, return 0."
  3085 
  3085 
  3086     ^ self findMatchString:matchString startingAt:1 ignoreCase:false ifAbsent:0 
  3086     ^ self findMatchString:matchString startingAt:1 ignoreCase:false ifAbsent:0
  3087 !
  3087 !
  3088 
  3088 
  3089 findMatchString:matchString startingAt:index
  3089 findMatchString:matchString startingAt:index
  3090     "like findString, but allowing match patterns.
  3090     "like findString, but allowing match patterns.
  3091      find matchstring, starting at index. if found, return the index;
  3091      find matchstring, starting at index. if found, return the index;
  3092      if not found, return 0."
  3092      if not found, return 0."
  3093 
  3093 
  3094     ^ self findMatchString:matchString startingAt:index ignoreCase:false ifAbsent:0 
  3094     ^ self findMatchString:matchString startingAt:index ignoreCase:false ifAbsent:0
  3095 !
  3095 !
  3096 
  3096 
  3097 findMatchString:matchString startingAt:index ignoreCase:ignoreCase ifAbsent:exceptionBlock
  3097 findMatchString:matchString startingAt:index ignoreCase:ignoreCase ifAbsent:exceptionBlock
  3098     "like findString, but allowing match patterns.
  3098     "like findString, but allowing match patterns.
  3099      find matchstring, starting at index. if found, return the index;
  3099      find matchstring, starting at index. if found, return the index;
  3109     matchSize := matchString size.
  3109     matchSize := matchString size.
  3110     matchSize == 0 ifTrue:[^ index]. "empty string matches"
  3110     matchSize == 0 ifTrue:[^ index]. "empty string matches"
  3111 
  3111 
  3112     realMatchString := matchString.
  3112     realMatchString := matchString.
  3113     (realMatchString endsWith:$*) ifFalse:[
  3113     (realMatchString endsWith:$*) ifFalse:[
  3114         realMatchString := realMatchString , '*'.
  3114 	realMatchString := realMatchString , '*'.
  3115         matchSize := matchSize + 1
  3115 	matchSize := matchSize + 1
  3116     ].
  3116     ].
  3117 
  3117 
  3118     mySize := self size.
  3118     mySize := self size.
  3119     firstChar := realMatchString at:1.
  3119     firstChar := realMatchString at:1.
  3120     firstChar == self class matchEscapeCharacter ifTrue:[
  3120     firstChar == self class matchEscapeCharacter ifTrue:[
  3121         firstChar := realMatchString at:2.
  3121 	firstChar := realMatchString at:2.
  3122     ].
  3122     ].
  3123 
  3123 
  3124     firstChar asString includesMatchCharacters ifTrue:[
  3124     firstChar asString includesMatchCharacters ifTrue:[
  3125         index to:mySize do:[:col |
  3125 	index to:mySize do:[:col |
  3126             (realMatchString match:self from:col to:mySize ignoreCase:ignoreCase)
  3126 	    (realMatchString match:self from:col to:mySize ignoreCase:ignoreCase)
  3127             ifTrue:[^ col]
  3127 	    ifTrue:[^ col]
  3128         ].
  3128 	].
  3129         ^ exceptionBlock value.
  3129 	^ exceptionBlock value.
  3130     ].
  3130     ].
  3131 
  3131 
  3132     lcChar := firstChar asLowercase.
  3132     lcChar := firstChar asLowercase.
  3133     ucChar := firstChar asUppercase.
  3133     ucChar := firstChar asUppercase.
  3134     (ignoreCase and:[ lcChar ~= ucChar]) ifTrue:[
  3134     (ignoreCase and:[ lcChar ~= ucChar]) ifTrue:[
  3135         firstSet := Array with:ucChar with:lcChar.
  3135 	firstSet := Array with:ucChar with:lcChar.
  3136         startIndex := self indexOfAny:firstSet startingAt:index.
  3136 	startIndex := self indexOfAny:firstSet startingAt:index.
  3137     ] ifFalse:[
  3137     ] ifFalse:[
  3138         startIndex := self indexOf:firstChar startingAt:index.
  3138 	startIndex := self indexOf:firstChar startingAt:index.
  3139     ].
  3139     ].
  3140     [startIndex == 0] whileFalse:[
  3140     [startIndex == 0] whileFalse:[
  3141         (realMatchString match:self from:startIndex to:mySize ignoreCase:ignoreCase)
  3141 	(realMatchString match:self from:startIndex to:mySize ignoreCase:ignoreCase)
  3142         ifTrue:[^ startIndex].
  3142 	ifTrue:[^ startIndex].
  3143         firstSet notNil ifTrue:[
  3143 	firstSet notNil ifTrue:[
  3144             startIndex := self indexOfAny:firstSet startingAt:(startIndex + 1).
  3144 	    startIndex := self indexOfAny:firstSet startingAt:(startIndex + 1).
  3145         ] ifFalse:[
  3145 	] ifFalse:[
  3146             startIndex := self indexOf:firstChar startingAt:(startIndex + 1).
  3146 	    startIndex := self indexOf:firstChar startingAt:(startIndex + 1).
  3147         ].
  3147 	].
  3148     ].
  3148     ].
  3149     ^ exceptionBlock value
  3149     ^ exceptionBlock value
  3150 
  3150 
  3151     "
  3151     "
  3152      'one two three four' findMatchString:'o[nu]'
  3152      'one two three four' findMatchString:'o[nu]'
  3153      'one two three four' findMatchString:'o[nu]' startingAt:3
  3153      'one two three four' findMatchString:'o[nu]' startingAt:3
  3154      'one two three four one' findMatchString:'ONE' startingAt:3 ignoreCase:true ifAbsent:0 
  3154      'one two three four one' findMatchString:'ONE' startingAt:3 ignoreCase:true ifAbsent:0
  3155     "
  3155     "
  3156 
  3156 
  3157     "Modified: 13.9.1997 / 06:31:22 / cg"
  3157     "Modified: 13.9.1997 / 06:31:22 / cg"
  3158 !
  3158 !
  3159 
  3159 
  3163 
  3163 
  3164     ^ (self findMatchString:matchString) ~~ 0
  3164     ^ (self findMatchString:matchString) ~~ 0
  3165 
  3165 
  3166     "
  3166     "
  3167      'hello world' includesMatchString:'h*'
  3167      'hello world' includesMatchString:'h*'
  3168      'hello world' includesMatchString:'h[aeiou]llo' 
  3168      'hello world' includesMatchString:'h[aeiou]llo'
  3169      'hello world' includesMatchString:'wor*'     
  3169      'hello world' includesMatchString:'wor*'
  3170      'hello world' includesMatchString:'woR*'     
  3170      'hello world' includesMatchString:'woR*'
  3171     "
  3171     "
  3172 !
  3172 !
  3173 
  3173 
  3174 match:aString
  3174 match:aString
  3175     "return true if aString matches self, where self may contain meta-match 
  3175     "return true if aString matches self, where self may contain meta-match
  3176      characters $* (to match any string) or $# (to match any character).
  3176      characters $* (to match any string) or $# (to match any character).
  3177      or [...] to match a set of characters.
  3177      or [...] to match a set of characters.
  3178      Lower/uppercase are considered different.
  3178      Lower/uppercase are considered different.
  3179      NOTICE: match-meta character interpretation is like in unix-matching, 
  3179      NOTICE: match-meta character interpretation is like in unix-matching,
  3180              NOT the ST-80 meaning."
  3180 	     NOT the ST-80 meaning."
  3181 
  3181 
  3182     ^ self match:aString from:1 to:aString size ignoreCase:false
  3182     ^ self match:aString from:1 to:aString size ignoreCase:false
  3183 
  3183 
  3184     "
  3184     "
  3185      '\*f*' match:'f' 
  3185      '\*f*' match:'f'
  3186      '\*f*' match:'*f' 
  3186      '\*f*' match:'*f'
  3187      '*\*f*' match:'*f' 
  3187      '*\*f*' match:'*f'
  3188      '*f*' match:'*f' 
  3188      '*f*' match:'*f'
  3189      '*ute*' match:'computer' 
  3189      '*ute*' match:'computer'
  3190      '*uter' match:'computer' 
  3190      '*uter' match:'computer'
  3191      'uter*' match:'computer' 
  3191      'uter*' match:'computer'
  3192      '*ute*' match:'' 
  3192      '*ute*' match:''
  3193      '[abcd]*' match:'computer' 
  3193      '[abcd]*' match:'computer'
  3194      '[abcd]*' match:'komputer' 
  3194      '[abcd]*' match:'komputer'
  3195      '*some*compl*ern*' match:'this is some more complicated pattern match' 
  3195      '*some*compl*ern*' match:'this is some more complicated pattern match'
  3196      '*some*compl*ern*' match:'this is another complicated pattern match' 
  3196      '*some*compl*ern*' match:'this is another complicated pattern match'
  3197      '*-hh' match:'anton-h'
  3197      '*-hh' match:'anton-h'
  3198     "
  3198     "
  3199 
  3199 
  3200     "Modified: / 9.6.1998 / 18:50:00 / cg"
  3200     "Modified: / 9.6.1998 / 18:50:00 / cg"
  3201 !
  3201 !
  3202 
  3202 
  3203 match:aString from:start to:stop ignoreCase:ignoreCase
  3203 match:aString from:start to:stop ignoreCase:ignoreCase
  3204     "return true if part of aString matches myself, 
  3204     "return true if part of aString matches myself,
  3205      where self may contain meta-match 
  3205      where self may contain meta-match
  3206      characters $* (to match any string) or $# (to match any character)
  3206      characters $* (to match any string) or $# (to match any character)
  3207      or [...] to match a set of characters.
  3207      or [...] to match a set of characters.
  3208      If ignoreCase is true, lower/uppercase are considered the same.
  3208      If ignoreCase is true, lower/uppercase are considered the same.
  3209      NOTICE: match-meta character interpretation is like in unix-matching, 
  3209      NOTICE: match-meta character interpretation is like in unix-matching,
  3210              NOT the ST-80 meaning."
  3210 	     NOT the ST-80 meaning."
  3211 
  3211 
  3212     |matchScanArray|
  3212     |matchScanArray|
  3213 
  3213 
  3214     "
  3214     "
  3215      keep the matchScanArray from the most recent match -
  3215      keep the matchScanArray from the most recent match -
  3216      avoids parsing the pattern over-and over if multiple searches
  3216      avoids parsing the pattern over-and over if multiple searches
  3217      are done with the same pattern.
  3217      are done with the same pattern.
  3218     "
  3218     "
  3219     (PreviousMatch notNil
  3219     (PreviousMatch notNil
  3220     and:[PreviousMatch key = self]) ifTrue:[
  3220     and:[PreviousMatch key = self]) ifTrue:[
  3221         matchScanArray := PreviousMatch value
  3221 	matchScanArray := PreviousMatch value
  3222     ] ifFalse:[
  3222     ] ifFalse:[
  3223         matchScanArray := self class matchScanArrayFrom:self.
  3223 	matchScanArray := self class matchScanArrayFrom:self.
  3224         matchScanArray isNil ifTrue:[
  3224 	matchScanArray isNil ifTrue:[
  3225             'CharacterArray [info]: invalid matchpattern:''' infoPrint. self infoPrint. ''' comparing for equality.' infoPrintCR.
  3225 	    'CharacterArray [info]: invalid matchpattern:''' infoPrint. self infoPrint. ''' comparing for equality.' infoPrintCR.
  3226             ^ self = aString    
  3226 	    ^ self = aString
  3227 "/            ^ false
  3227 "/            ^ false
  3228         ].
  3228 	].
  3229         PreviousMatch := self -> matchScanArray.
  3229 	PreviousMatch := self -> matchScanArray.
  3230     ].
  3230     ].
  3231 
  3231 
  3232     ^ self class
  3232     ^ self class
  3233         matchScan:matchScanArray 
  3233 	matchScan:matchScanArray
  3234         from:1 to:matchScanArray size
  3234 	from:1 to:matchScanArray size
  3235         with:aString 
  3235 	with:aString
  3236         from:start to:stop 
  3236 	from:start to:stop
  3237         ignoreCase:ignoreCase
  3237 	ignoreCase:ignoreCase
  3238 
  3238 
  3239     "
  3239     "
  3240      '*ute*' match:'12345COMPUTER' from:1 to:5 ignoreCase:true 
  3240      '*ute*' match:'12345COMPUTER' from:1 to:5 ignoreCase:true
  3241      '*ute*' match:'12345COMPUTER' from:6 to:13 ignoreCase:true  
  3241      '*ute*' match:'12345COMPUTER' from:6 to:13 ignoreCase:true
  3242     "
  3242     "
  3243 
  3243 
  3244     "Modified: / 10.11.1998 / 21:43:46 / cg"
  3244     "Modified: / 10.11.1998 / 21:43:46 / cg"
  3245 !
  3245 !
  3246 
  3246 
  3247 match:aString ignoreCase:ignoreCase
  3247 match:aString ignoreCase:ignoreCase
  3248     "return true if aString matches self, where self may contain meta-match 
  3248     "return true if aString matches self, where self may contain meta-match
  3249      characters $* (to match any string) or $# (to match any character)
  3249      characters $* (to match any string) or $# (to match any character)
  3250      or [...] to match a set of characters.
  3250      or [...] to match a set of characters.
  3251      If ignoreCase is true, lower/uppercase are considered the same.
  3251      If ignoreCase is true, lower/uppercase are considered the same.
  3252      NOTICE: match-meta character interpretation is like in unix-matching, 
  3252      NOTICE: match-meta character interpretation is like in unix-matching,
  3253              NOT the ST-80 meaning."
  3253 	     NOT the ST-80 meaning."
  3254 
  3254 
  3255     ^ self match:aString from:1 to:aString size ignoreCase:ignoreCase
  3255     ^ self match:aString from:1 to:aString size ignoreCase:ignoreCase
  3256 
  3256 
  3257     "
  3257     "
  3258      '*ute*' match:'COMPUTER' ignoreCase:true  
  3258      '*ute*' match:'COMPUTER' ignoreCase:true
  3259      '*uter' match:'COMPUTER' ignoreCase:false 
  3259      '*uter' match:'COMPUTER' ignoreCase:false
  3260      '[abcd]*' match:'computer' ignoreCase:false 
  3260      '[abcd]*' match:'computer' ignoreCase:false
  3261      '[abcd]*' match:'Computer' ignoreCase:false 
  3261      '[abcd]*' match:'Computer' ignoreCase:false
  3262      '[a-k]*' match:'komputer' ignoreCase:false   
  3262      '[a-k]*' match:'komputer' ignoreCase:false
  3263      '[a-k]*' match:'zomputer' ignoreCase:false    
  3263      '[a-k]*' match:'zomputer' ignoreCase:false
  3264      '[a-k]*' match:'Komputer' ignoreCase:false    
  3264      '[a-k]*' match:'Komputer' ignoreCase:false
  3265      '[a-k]*' match:'Komputer' ignoreCase:true     
  3265      '[a-k]*' match:'Komputer' ignoreCase:true
  3266      '*some*compl*ern*' match:'this is some more complicated pattern match' ignoreCase:true 
  3266      '*some*compl*ern*' match:'this is some more complicated pattern match' ignoreCase:true
  3267      '*some*compl*ern*' match:'this is another complicated pattern match' ignoreCase:true 
  3267      '*some*compl*ern*' match:'this is another complicated pattern match' ignoreCase:true
  3268 
  3268 
  3269      Time millisecondsToRun:[
  3269      Time millisecondsToRun:[
  3270         Symbol allInstancesDo:[:sym |
  3270 	Symbol allInstancesDo:[:sym |
  3271             '[ab]*' match:sym ignoreCase:false
  3271 	    '[ab]*' match:sym ignoreCase:false
  3272         ]
  3272 	]
  3273      ]. 
  3273      ].
  3274      Time millisecondsToRun:[
  3274      Time millisecondsToRun:[
  3275         Symbol allInstancesDo:[:sym |
  3275 	Symbol allInstancesDo:[:sym |
  3276             '*at:*' match:sym ignoreCase:false
  3276 	    '*at:*' match:sym ignoreCase:false
  3277         ]
  3277 	]
  3278      ]. 
  3278      ].
  3279     "
  3279     "
  3280 
  3280 
  3281     "Modified: 2.4.1997 / 17:28:58 / cg"
  3281     "Modified: 2.4.1997 / 17:28:58 / cg"
  3282 !
  3282 !
  3283 
  3283 
  3284 matches:aPatternString
  3284 matches:aPatternString
  3285     "return true if the receiver matches aString, where aPatternString may contain meta-match 
  3285     "return true if the receiver matches aString, where aPatternString may contain meta-match
  3286      characters $* (to match any string) or $# (to match any character).
  3286      characters $* (to match any string) or $# (to match any character).
  3287      or [...] to match a set of characters.
  3287      or [...] to match a set of characters.
  3288      Lower/uppercase are considered different.
  3288      Lower/uppercase are considered different.
  3289      NOTICE: match-meta character interpretation is like in unix-matching, 
  3289      NOTICE: match-meta character interpretation is like in unix-matching,
  3290              NOT the ST-80 meaning."
  3290 	     NOT the ST-80 meaning."
  3291 
  3291 
  3292     ^ aPatternString match:self
  3292     ^ aPatternString match:self
  3293 
  3293 
  3294 
  3294 
  3295 ! !
  3295 ! !
  3299 article
  3299 article
  3300     "return an article string for the receiver."
  3300     "return an article string for the receiver."
  3301 
  3301 
  3302     |firstChar|
  3302     |firstChar|
  3303 
  3303 
  3304     firstChar := (self at:1) asLowercase. 
  3304     firstChar := (self at:1) asLowercase.
  3305     ((firstChar isVowel and:[firstChar ~~ $u]) or:[firstChar == $x]) ifTrue:[
  3305     ((firstChar isVowel and:[firstChar ~~ $u]) or:[firstChar == $x]) ifTrue:[
  3306         ^ 'an'
  3306 	^ 'an'
  3307     ].
  3307     ].
  3308     ^ 'a'
  3308     ^ 'a'
  3309 
  3309 
  3310     "
  3310     "
  3311         'uboot' article.
  3311 	'uboot' article.
  3312         'xmas' article.
  3312 	'xmas' article.
  3313         'alarm' article.
  3313 	'alarm' article.
  3314         'baby' article.
  3314 	'baby' article.
  3315     "
  3315     "
  3316 !
  3316 !
  3317 
  3317 
  3318 basicStoreString
  3318 basicStoreString
  3319     "return a String for storing myself"
  3319     "return a String for storing myself"
  3320 
  3320 
  3321     |s n index|
  3321     |s n index|
  3322 
  3322 
  3323     n := self occurrencesOf:$'.
  3323     n := self occurrencesOf:$'.
  3324     n == 0 ifFalse:[
  3324     n == 0 ifFalse:[
  3325         s := String new:(n + 2 + self size).
  3325 	s := String new:(n + 2 + self size).
  3326         s at:1 put:$'.
  3326 	s at:1 put:$'.
  3327         index := 2.
  3327 	index := 2.
  3328         self do:[:thisChar |
  3328 	self do:[:thisChar |
  3329             (thisChar == $') ifTrue:[
  3329 	    (thisChar == $') ifTrue:[
  3330                 s at:index put:thisChar.
  3330 		s at:index put:thisChar.
  3331                 index := index + 1.
  3331 		index := index + 1.
  3332             ].
  3332 	    ].
  3333             s at:index put:thisChar.
  3333 	    s at:index put:thisChar.
  3334             index := index + 1.
  3334 	    index := index + 1.
  3335         ].
  3335 	].
  3336         s at:index put:$'.
  3336 	s at:index put:$'.
  3337         ^ s
  3337 	^ s
  3338     ].
  3338     ].
  3339     ^ '''' , self , ''''
  3339     ^ '''' , self , ''''
  3340 !
  3340 !
  3341 
  3341 
  3342 displayString
  3342 displayString
  3359 
  3359 
  3360 printWithQuotesDoubledOn:aStream
  3360 printWithQuotesDoubledOn:aStream
  3361     "put the raw storeString of myself on aStream"
  3361     "put the raw storeString of myself on aStream"
  3362 
  3362 
  3363     self do:[:thisChar |
  3363     self do:[:thisChar |
  3364         (thisChar == $') ifTrue:[aStream nextPut:thisChar].
  3364 	(thisChar == $') ifTrue:[aStream nextPut:thisChar].
  3365         aStream nextPut:thisChar
  3365 	aStream nextPut:thisChar
  3366     ]
  3366     ]
  3367 
  3367 
  3368     "Modified: / 15.6.1998 / 17:21:17 / cg"
  3368     "Modified: / 15.6.1998 / 17:21:17 / cg"
  3369     "Created: / 15.6.1998 / 17:22:13 / cg"
  3369     "Created: / 15.6.1998 / 17:22:13 / cg"
  3370 ! !
  3370 ! !
  3371 
  3371 
  3372 !CharacterArray methodsFor:'public'!
  3372 !CharacterArray methodsFor:'public'!
  3373 
  3373 
  3374 isUnarySelector 
  3374 isUnarySelector
  3375     "Answer true if the receiver contains only chars in an ANSI unary method selector, false otherwise."
  3375     "Answer true if the receiver contains only chars in an ANSI unary method selector, false otherwise."
  3376 
  3376 
  3377     ^ (self first isLetter or:[ self first = $_ ])
  3377     ^ (self first isLetter or:[ self first = $_ ])
  3378       and:[ self allSatisfy: [ :chr | chr isLetterOrDigit ]]
  3378       and:[ self allSatisfy: [ :chr | chr isLetterOrDigit ]]
  3379 
  3379 
  3381 ! !
  3381 ! !
  3382 
  3382 
  3383 !CharacterArray methodsFor:'queries'!
  3383 !CharacterArray methodsFor:'queries'!
  3384 
  3384 
  3385 bitsPerCharacter
  3385 bitsPerCharacter
  3386     "return the underlying strings bitsPerCharacter 
  3386     "return the underlying strings bitsPerCharacter
  3387      (i.e. is it a regular String or a TwoByteString)"
  3387      (i.e. is it a regular String or a TwoByteString)"
  3388 
  3388 
  3389     |string max|
  3389     |string max|
  3390 
  3390 
  3391     (string := self string) ~~ self ifTrue:[
  3391     (string := self string) ~~ self ifTrue:[
  3392         ^ string bitsPerCharacter
  3392 	^ string bitsPerCharacter
  3393     ].
  3393     ].
  3394 
  3394 
  3395     max := 8.
  3395     max := 8.
  3396     self do:[:eachCharacter |
  3396     self do:[:eachCharacter |
  3397         max := max max:(eachCharacter bitsPerCharacter)
  3397 	max := max max:(eachCharacter bitsPerCharacter)
  3398     ].
  3398     ].
  3399     ^ max
  3399     ^ max
  3400 
  3400 
  3401     "
  3401     "
  3402      'hello' bitsPerCharacter                
  3402      'hello' bitsPerCharacter
  3403      'hello' asText allBold bitsPerCharacter   
  3403      'hello' asText allBold bitsPerCharacter
  3404     "
  3404     "
  3405 !
  3405 !
  3406 
  3406 
  3407 contains8BitCharacters
  3407 contains8BitCharacters
  3408     "return true, if the underlying string contains 8BitCharacters (or widers) 
  3408     "return true, if the underlying string contains 8BitCharacters (or widers)
  3409      (i.e. if it is non-ascii)"
  3409      (i.e. if it is non-ascii)"
  3410 
  3410 
  3411     |string|
  3411     |string|
  3412 
  3412 
  3413     (string := self string) ~~ self ifTrue:[
  3413     (string := self string) ~~ self ifTrue:[
  3414         ^ string contains8BitCharacters
  3414 	^ string contains8BitCharacters
  3415     ].
  3415     ].
  3416     self do:[:eachCharacter |
  3416     self do:[:eachCharacter |
  3417         (eachCharacter codePoint > 16r7F) ifTrue:[
  3417 	(eachCharacter codePoint > 16r7F) ifTrue:[
  3418             ^ true
  3418 	    ^ true
  3419         ].
  3419 	].
  3420     ].
  3420     ].
  3421     ^ false
  3421     ^ false
  3422 
  3422 
  3423     "
  3423     "
  3424      'hello' contains8BitCharacters        
  3424      'hello' contains8BitCharacters
  3425      'hello' asText allBold contains8BitCharacters 
  3425      'hello' asText allBold contains8BitCharacters
  3426     "
  3426     "
  3427 !
  3427 !
  3428 
  3428 
  3429 encoding
  3429 encoding
  3430     "return the strings encoding, as a symbol.
  3430     "return the strings encoding, as a symbol.
  3431      Here, by default, we assume unicode-encoding.
  3431      Here, by default, we assume unicode-encoding.
  3432      Notice, that iso8859-1 is a true subset of unicode,
  3432      Notice, that iso8859-1 is a true subset of unicode,
  3433      and that singleByteStrings are therefore both unicode AND 
  3433      and that singleByteStrings are therefore both unicode AND
  3434      8859-1 encoded."
  3434      8859-1 encoded."
  3435 
  3435 
  3436     ^ #'unicode'
  3436     ^ #'unicode'
  3437 !
  3437 !
  3438 
  3438 
  3458     "return the size of the recevier in device units if displayed on aGC"
  3458     "return the size of the recevier in device units if displayed on aGC"
  3459 
  3459 
  3460     ^ (aGC font onDevice:aGC device) heightOf:self
  3460     ^ (aGC font onDevice:aGC device) heightOf:self
  3461 
  3461 
  3462     "
  3462     "
  3463      'hello world' heightOn:(View new)                 
  3463      'hello world' heightOn:(View new)
  3464     "
  3464     "
  3465 
  3465 
  3466     "Created: 12.5.1996 / 20:09:29 / cg"
  3466     "Created: 12.5.1996 / 20:09:29 / cg"
  3467     "Modified: 12.5.1996 / 20:32:05 / cg"
  3467     "Modified: 12.5.1996 / 20:32:05 / cg"
  3468 !
  3468 !
  3481 
  3481 
  3482     scanner := Compiler new.
  3482     scanner := Compiler new.
  3483     scanner source:(self readStream).
  3483     scanner source:(self readStream).
  3484     tok := scanner nextToken.
  3484     tok := scanner nextToken.
  3485     tok ~~ #Identifier ifTrue:[
  3485     tok ~~ #Identifier ifTrue:[
  3486         ^ false
  3486 	^ false
  3487     ].
  3487     ].
  3488     scanner tokenPosition == 1 ifFalse:[^ false].
  3488     scanner tokenPosition == 1 ifFalse:[^ false].
  3489     ^ scanner sourceStream atEnd.
  3489     ^ scanner sourceStream atEnd.
  3490 
  3490 
  3491     "
  3491     "
  3492      'foo' isValidSmalltalkIdentifier  
  3492      'foo' isValidSmalltalkIdentifier
  3493      '1foo' isValidSmalltalkIdentifier  
  3493      '1foo' isValidSmalltalkIdentifier
  3494      '_foo' isValidSmalltalkIdentifier  
  3494      '_foo' isValidSmalltalkIdentifier
  3495      '_foo_bar_' isValidSmalltalkIdentifier  
  3495      '_foo_bar_' isValidSmalltalkIdentifier
  3496      'foo ' isValidSmalltalkIdentifier      
  3496      'foo ' isValidSmalltalkIdentifier
  3497      ' foo' isValidSmalltalkIdentifier      
  3497      ' foo' isValidSmalltalkIdentifier
  3498     "
  3498     "
  3499 !
  3499 !
  3500 
  3500 
  3501 leftIndent
  3501 leftIndent
  3502     "if the receiver starts with spaces, return the number of spaces
  3502     "if the receiver starts with spaces, return the number of spaces
  3507      end   "{Class: SmallInteger }"|
  3507      end   "{Class: SmallInteger }"|
  3508 
  3508 
  3509     index := 1.
  3509     index := 1.
  3510     end := self size.
  3510     end := self size.
  3511     [index <= end] whileTrue:[
  3511     [index <= end] whileTrue:[
  3512         (self at:index) isSeparator ifFalse:[^ index - 1].
  3512 	(self at:index) isSeparator ifFalse:[^ index - 1].
  3513         index := index + 1
  3513 	index := index + 1
  3514     ].
  3514     ].
  3515     ^ end
  3515     ^ end
  3516 
  3516 
  3517     "
  3517     "
  3518      '    hello' leftIndent 
  3518      '    hello' leftIndent
  3519      'foo      ' leftIndent 
  3519      'foo      ' leftIndent
  3520      '         ' leftIndent 
  3520      '         ' leftIndent
  3521     "
  3521     "
  3522 
  3522 
  3523     "Modified: 20.4.1996 / 19:28:43 / cg"
  3523     "Modified: 20.4.1996 / 19:28:43 / cg"
  3524 !
  3524 !
  3525 
  3525 
  3526 stringSpecies
  3526 stringSpecies
  3527     "return the underlying strings bitsPerCharacter 
  3527     "return the underlying strings bitsPerCharacter
  3528      (i.e. is it a regular String or a TwoByteString)"
  3528      (i.e. is it a regular String or a TwoByteString)"
  3529 
  3529 
  3530     |string|
  3530     |string|
  3531 
  3531 
  3532     (string := self string) == self ifTrue:[^ self class].
  3532     (string := self string) == self ifTrue:[^ self class].
  3533     ^ string stringSpecies
  3533     ^ string stringSpecies
  3534 
  3534 
  3535     "
  3535     "
  3536      'hello' stringSpecies        
  3536      'hello' stringSpecies
  3537      'hello' asText allBold stringSpecies 
  3537      'hello' asText allBold stringSpecies
  3538     "
  3538     "
  3539 !
  3539 !
  3540 
  3540 
  3541 widthFrom:startIndex to:endIndex on:aGC
  3541 widthFrom:startIndex to:endIndex on:aGC
  3542     "return ths size of part of the recevier in device units if displayed on aGC"
  3542     "return ths size of part of the recevier in device units if displayed on aGC"
  3543 
  3543 
  3544     ^ (aGC font onDevice:aGC device) widthOf:self from:startIndex to:endIndex
  3544     ^ (aGC font onDevice:aGC device) widthOf:self from:startIndex to:endIndex
  3545 
  3545 
  3546     "
  3546     "
  3547      'hello world' widthFrom:1 to:5 on:(View new)                 
  3547      'hello world' widthFrom:1 to:5 on:(View new)
  3548      'hello' widthOn:(View new)                      
  3548      'hello' widthOn:(View new)
  3549     "
  3549     "
  3550 !
  3550 !
  3551 
  3551 
  3552 widthOn:aGC
  3552 widthOn:aGC
  3553     "return ths size of the recevier in device units if displayed on aGC"
  3553     "return ths size of the recevier in device units if displayed on aGC"
  3554 
  3554 
  3555     ^ (aGC font onDevice:aGC device) widthOf:self
  3555     ^ (aGC font onDevice:aGC device) widthOf:self
  3556 
  3556 
  3557     "
  3557     "
  3558      'hello world' widthOn:(View new)                 
  3558      'hello world' widthOn:(View new)
  3559     "
  3559     "
  3560 
  3560 
  3561     "Created: 12.5.1996 / 20:09:29 / cg"
  3561     "Created: 12.5.1996 / 20:09:29 / cg"
  3562     "Modified: 17.4.1997 / 12:50:23 / cg"
  3562     "Modified: 17.4.1997 / 12:50:23 / cg"
  3563 ! !
  3563 ! !
  3568     "return a collection of substrings in the receiver, which match the regular expression in rxString"
  3568     "return a collection of substrings in the receiver, which match the regular expression in rxString"
  3569 
  3569 
  3570     ^ rxString asRegex matchesIn: self
  3570     ^ rxString asRegex matchesIn: self
  3571 
  3571 
  3572     "
  3572     "
  3573      '1234 abcd 3456 defg' allRegexMatches:'[0-9]+'    
  3573      '1234 abcd 3456 defg' allRegexMatches:'[0-9]+'
  3574 
  3574 
  3575      '[0-9]+' asRegex matchesIn:'1234 abcd 3456 defg'
  3575      '[0-9]+' asRegex matchesIn:'1234 abcd 3456 defg'
  3576     "
  3576     "
  3577 !
  3577 !
  3578 
  3578 
  3579 asRegex
  3579 asRegex
  3580     "Compile the receiver as a regex matcher. 
  3580     "Compile the receiver as a regex matcher.
  3581      May raise RxParser>>syntaxErrorSignal or RxParser>>compilationErrorSignal.
  3581      May raise RxParser>>syntaxErrorSignal or RxParser>>compilationErrorSignal.
  3582      This is a part of the Regular Expression Matcher package, 
  3582      This is a part of the Regular Expression Matcher package,
  3583         (c) 1996, 1999 Vassili Bykov.
  3583 	(c) 1996, 1999 Vassili Bykov.
  3584      Refer to `documentation' protocol of RxParser class for details."
  3584      Refer to `documentation' protocol of RxParser class for details."
  3585 
  3585 
  3586     ^ Regex::RxParser preferredMatcherClass 
  3586     ^ Regex::RxParser preferredMatcherClass
  3587         for: (Regex::RxParser new parse: self)
  3587 	for: (Regex::RxParser new parse: self)
  3588 !
  3588 !
  3589 
  3589 
  3590 asRegexIgnoringCase
  3590 asRegexIgnoringCase
  3591     "Compile the receiver as a regex matcher. 
  3591     "Compile the receiver as a regex matcher.
  3592      May raise RxParser>>syntaxErrorSignal or RxParser>>compilationErrorSignal.
  3592      May raise RxParser>>syntaxErrorSignal or RxParser>>compilationErrorSignal.
  3593      This is a part of the Regular Expression Matcher package, 
  3593      This is a part of the Regular Expression Matcher package,
  3594         (c) 1996, 1999 Vassili Bykov.
  3594 	(c) 1996, 1999 Vassili Bykov.
  3595      Refer to `documentation' protocol of RxParser class for details."
  3595      Refer to `documentation' protocol of RxParser class for details."
  3596 
  3596 
  3597     ^ Regex::RxParser preferredMatcherClass
  3597     ^ Regex::RxParser preferredMatcherClass
  3598             for: (Regex::RxParser new parse: self)
  3598 	    for: (Regex::RxParser new parse: self)
  3599             ignoreCase: true
  3599 	    ignoreCase: true
  3600 !
  3600 !
  3601 
  3601 
  3602 copyWithRegex: rxString matchesReplacedWith: aString
  3602 copyWithRegex: rxString matchesReplacedWith: aString
  3603     ^ rxString asRegex copy: self replacingMatchesWith: aString
  3603     ^ rxString asRegex copy: self replacingMatchesWith: aString
  3604 !
  3604 !
  3606 copyWithRegex: rxString matchesTranslatedUsing: aBlock
  3606 copyWithRegex: rxString matchesTranslatedUsing: aBlock
  3607     ^ rxString asRegex copy: self translatingMatchesUsing: aBlock
  3607     ^ rxString asRegex copy: self translatingMatchesUsing: aBlock
  3608 !
  3608 !
  3609 
  3609 
  3610 matchesRegex: regexString
  3610 matchesRegex: regexString
  3611     "Test if the receiver matches a regex.  
  3611     "Test if the receiver matches a regex.
  3612      May raise RxParser>>regexErrorSignal or child signals.
  3612      May raise RxParser>>regexErrorSignal or child signals.
  3613      This is a part of the Regular Expression Matcher package, 
  3613      This is a part of the Regular Expression Matcher package,
  3614         (c) 1996, 1999 Vassili Bykov.
  3614 	(c) 1996, 1999 Vassili Bykov.
  3615      Refer to `documentation' protocol of RxParser class for details."
  3615      Refer to `documentation' protocol of RxParser class for details."
  3616 
  3616 
  3617     ^regexString asRegex matches: self
  3617     ^regexString asRegex matches: self
  3618 
  3618 
  3619     "
  3619     "
  3620      'hello world' matchesRegex:'h.*d'.
  3620      'hello world' matchesRegex:'h.*d'.
  3621     "
  3621     "
  3622 !
  3622 !
  3623 
  3623 
  3624 matchesRegexIgnoringCase: regexString
  3624 matchesRegexIgnoringCase: regexString
  3625     "Test if the receiver matches a regex.  
  3625     "Test if the receiver matches a regex.
  3626      May raise RxParser>>regexErrorSignal or child signals.
  3626      May raise RxParser>>regexErrorSignal or child signals.
  3627      This is a part of the Regular Expression Matcher package, 
  3627      This is a part of the Regular Expression Matcher package,
  3628         (c) 1996, 1999 Vassili Bykov.
  3628 	(c) 1996, 1999 Vassili Bykov.
  3629      Refer to `documentation' protocol of RxParser class for details."
  3629      Refer to `documentation' protocol of RxParser class for details."
  3630 
  3630 
  3631     ^regexString asRegexIgnoringCase matches: self
  3631     ^regexString asRegexIgnoringCase matches: self
  3632 
  3632 
  3633     "
  3633     "
  3634      'hElLo wOrld' matchesRegexIgnoringCase:'h.*d'.
  3634      'hElLo wOrld' matchesRegexIgnoringCase:'h.*d'.
  3635     "
  3635     "
  3636 !
  3636 !
  3637 
  3637 
  3638 prefixMatchesRegex: regexString
  3638 prefixMatchesRegex: regexString
  3639     "Test if the receiver's prefix matches a regex.         
  3639     "Test if the receiver's prefix matches a regex.
  3640      May raise RxParser class>>regexErrorSignal or child signals.
  3640      May raise RxParser class>>regexErrorSignal or child signals.
  3641      This is a part of the Regular Expression Matcher package, 
  3641      This is a part of the Regular Expression Matcher package,
  3642         (c) 1996, 1999 Vassili Bykov.
  3642 	(c) 1996, 1999 Vassili Bykov.
  3643      Refer to `documentation' protocol of RxParser class for details."
  3643      Refer to `documentation' protocol of RxParser class for details."
  3644 
  3644 
  3645     ^regexString asRegex matchesPrefix: self
  3645     ^regexString asRegex matchesPrefix: self
  3646 !
  3646 !
  3647 
  3647 
  3648 prefixMatchesRegexIgnoringCase: regexString
  3648 prefixMatchesRegexIgnoringCase: regexString
  3649     "Test if the receiver's prefix matches a regex.         
  3649     "Test if the receiver's prefix matches a regex.
  3650      May raise RxParser class>>regexErrorSignal or child signals.
  3650      May raise RxParser class>>regexErrorSignal or child signals.
  3651      This is a part of the Regular Expression Matcher package, 
  3651      This is a part of the Regular Expression Matcher package,
  3652         (c) 1996, 1999 Vassili Bykov.
  3652 	(c) 1996, 1999 Vassili Bykov.
  3653      Refer to `documentation' protocol of RxParser class for details."
  3653      Refer to `documentation' protocol of RxParser class for details."
  3654 
  3654 
  3655     ^regexString asRegexIgnoringCase matchesPrefix: self
  3655     ^regexString asRegexIgnoringCase matchesPrefix: self
  3656 !
  3656 !
  3657 
  3657 
  3660      and collect the returned values."
  3660      and collect the returned values."
  3661 
  3661 
  3662     ^ rxString asRegex matchesIn: self collect: aBlock
  3662     ^ rxString asRegex matchesIn: self collect: aBlock
  3663 
  3663 
  3664     "
  3664     "
  3665      'hello world' regex:'\w+' matchesCollect:[:each | each asUppercase ].    
  3665      'hello world' regex:'\w+' matchesCollect:[:each | each asUppercase ].
  3666      '1234 hello 456 world' regex:'\d+' matchesCollect:[:each | Number readFrom:each ].    
  3666      '1234 hello 456 world' regex:'\d+' matchesCollect:[:each | Number readFrom:each ].
  3667     "
  3667     "
  3668 !
  3668 !
  3669 
  3669 
  3670 regex:rxString matchesDo: aBlock
  3670 regex:rxString matchesDo: aBlock
  3671     "for all substrings in the receiver which match the regular expression in rxString, evaluate aBlock"
  3671     "for all substrings in the receiver which match the regular expression in rxString, evaluate aBlock"
  3679 
  3679 
  3680 !CharacterArray methodsFor:'special string converting'!
  3680 !CharacterArray methodsFor:'special string converting'!
  3681 
  3681 
  3682 chopTo:maxLen
  3682 chopTo:maxLen
  3683     "if the receivers size is less or equal to maxLen, return it.
  3683     "if the receivers size is less or equal to maxLen, return it.
  3684      Otherwise, return a copy of the receiver, where some characters 
  3684      Otherwise, return a copy of the receiver, where some characters
  3685      in the middle have been removed for a total string length
  3685      in the middle have been removed for a total string length
  3686      of maxLen."
  3686      of maxLen."
  3687 
  3687 
  3688     |sz n1 n2|
  3688     |sz n1 n2|
  3689 
  3689 
  3694 	].
  3694 	].
  3695 	^ (self copyFrom:1 to:n1) , (self copyFrom:sz - n2 + 1)
  3695 	^ (self copyFrom:1 to:n1) , (self copyFrom:sz - n2 + 1)
  3696     ]
  3696     ]
  3697 
  3697 
  3698     "
  3698     "
  3699      '12345678901234'   chopTo:15            
  3699      '12345678901234'   chopTo:15
  3700      '123456789012345'  chopTo:15         
  3700      '123456789012345'  chopTo:15
  3701      '1234567890123456' chopTo:15      
  3701      '1234567890123456' chopTo:15
  3702      'aShortString' chopTo:15 
  3702      'aShortString' chopTo:15
  3703      'aVeryLongNameForAStringThatShouldBeShortened' chopTo:15 
  3703      'aVeryLongNameForAStringThatShouldBeShortened' chopTo:15
  3704     "
  3704     "
  3705 !
  3705 !
  3706 
  3706 
  3707 contractAtBeginningTo:maxLen
  3707 contractAtBeginningTo:maxLen
  3708     "if the receivers size is less or equal to maxLen, return it.
  3708     "if the receivers size is less or equal to maxLen, return it.
  3709      Otherwise, return a copy of the receiver, where some characters 
  3709      Otherwise, return a copy of the receiver, where some characters
  3710      at the beginning have been replaced by '...' for a total string length
  3710      at the beginning have been replaced by '...' for a total string length
  3711      of maxLen. Can be used to abbreviate long entries in tables."
  3711      of maxLen. Can be used to abbreviate long entries in tables."
  3712 
  3712 
  3713     |sz|
  3713     |sz|
  3714 
  3714 
  3715     (sz := self size) > maxLen ifTrue:[
  3715     (sz := self size) > maxLen ifTrue:[
  3716 	^ '...' , (self copyFrom:(sz - (maxLen - 4))) 
  3716 	^ '...' , (self copyFrom:(sz - (maxLen - 4)))
  3717     ]
  3717     ]
  3718 
  3718 
  3719     "
  3719     "
  3720      '12345678901234' contractAtBeginningTo:15          
  3720      '12345678901234' contractAtBeginningTo:15
  3721      '123456789012345' contractAtBeginningTo:15          
  3721      '123456789012345' contractAtBeginningTo:15
  3722      '1234567890123456' contractAtBeginningTo:15          
  3722      '1234567890123456' contractAtBeginningTo:15
  3723      'aShortString' contractAtBeginningTo:15          
  3723      'aShortString' contractAtBeginningTo:15
  3724      'aVeryLongNameForAStringThatShouldBeShortened' contractAtBeginningTo:15
  3724      'aVeryLongNameForAStringThatShouldBeShortened' contractAtBeginningTo:15
  3725     "
  3725     "
  3726 !
  3726 !
  3727 
  3727 
  3728 contractAtEndTo:maxLen
  3728 contractAtEndTo:maxLen
  3729     "if the receivers size is less or equal to maxLen, return it.
  3729     "if the receivers size is less or equal to maxLen, return it.
  3730      Otherwise, return a copy of the receiver, where some characters 
  3730      Otherwise, return a copy of the receiver, where some characters
  3731      at the end have been replaced by '...' for a total string length
  3731      at the end have been replaced by '...' for a total string length
  3732      of maxLen. Can be used to abbreviate long entries in tables."
  3732      of maxLen. Can be used to abbreviate long entries in tables."
  3733 
  3733 
  3734     |sz|
  3734     |sz|
  3735 
  3735 
  3737 	^ self copyReplaceFrom:maxLen - 3
  3737 	^ self copyReplaceFrom:maxLen - 3
  3738 			    with:'...'
  3738 			    with:'...'
  3739     ]
  3739     ]
  3740 
  3740 
  3741     "
  3741     "
  3742      '12345678901234' contractAtEndTo:15          
  3742      '12345678901234' contractAtEndTo:15
  3743      '123456789012345' contractAtEndTo:15          
  3743      '123456789012345' contractAtEndTo:15
  3744      '1234567890123456' contractAtEndTo:15          
  3744      '1234567890123456' contractAtEndTo:15
  3745      'aShortString' contractAtEndTo:15          
  3745      'aShortString' contractAtEndTo:15
  3746      'aVeryLongNameForAStringThatShouldBeShortened' contractAtEndTo:15 
  3746      'aVeryLongNameForAStringThatShouldBeShortened' contractAtEndTo:15
  3747     "
  3747     "
  3748 !
  3748 !
  3749 
  3749 
  3750 contractTo:maxLen
  3750 contractTo:maxLen
  3751     "if the receivers size is less or equal to maxLen, return it.
  3751     "if the receivers size is less or equal to maxLen, return it.
  3752      Otherwise, return a copy of the receiver, where some characters 
  3752      Otherwise, return a copy of the receiver, where some characters
  3753      in the middle have been replaced by '...' for a total string length
  3753      in the middle have been replaced by '...' for a total string length
  3754      of maxLen. Can be used to abbreviate long entries in tables."
  3754      of maxLen. Can be used to abbreviate long entries in tables."
  3755 
  3755 
  3756     |sz "{ SmallInteger }"
  3756     |sz "{ SmallInteger }"
  3757      halfSize "{ SmallInteger }"|
  3757      halfSize "{ SmallInteger }"|
  3762 			    to:sz - maxLen + halfSize + 1
  3762 			    to:sz - maxLen + halfSize + 1
  3763 			    with:'...'
  3763 			    with:'...'
  3764     ]
  3764     ]
  3765 
  3765 
  3766     "
  3766     "
  3767      '12345678901234' contractTo:15          
  3767      '12345678901234' contractTo:15
  3768      '123456789012345' contractTo:15          
  3768      '123456789012345' contractTo:15
  3769      '1234567890123456' contractTo:15        
  3769      '1234567890123456' contractTo:15
  3770      'aShortString' contractTo:15 
  3770      'aShortString' contractTo:15
  3771      'aVeryLongNameForAStringThatShouldBeShortened' contractTo:15 
  3771      'aVeryLongNameForAStringThatShouldBeShortened' contractTo:15
  3772     "
  3772     "
  3773 !
  3773 !
  3774 
  3774 
  3775 expandPlaceholdersWith:argArrayOrDictionary
  3775 expandPlaceholdersWith:argArrayOrDictionary
  3776     "return a copy of the receiver, where all %i escapes are
  3776     "return a copy of the receiver, where all %i escapes are
  3794 
  3794 
  3795     expandedString := self species new:0.
  3795     expandedString := self species new:0.
  3796     stop := self size.
  3796     stop := self size.
  3797     start := 1.
  3797     start := 1.
  3798     [start <= stop] whileTrue:[
  3798     [start <= stop] whileTrue:[
  3799         idx := self indexOf:$% startingAt:start.
  3799 	idx := self indexOf:$% startingAt:start.
  3800         (idx == 0 or:[idx == stop]) ifTrue:[
  3800 	(idx == 0 or:[idx == stop]) ifTrue:[
  3801             ^ expandedString , (self copyFrom:start to:stop)
  3801 	    ^ expandedString , (self copyFrom:start to:stop)
  3802         ].
  3802 	].
  3803         "found a %"
  3803 	"found a %"
  3804         expandedString := expandedString , (self copyFrom:start to:(idx - 1)).
  3804 	expandedString := expandedString , (self copyFrom:start to:(idx - 1)).
  3805         next := self at:(idx + 1).
  3805 	next := self at:(idx + 1).
  3806         (next == $%) ifTrue:[
  3806 	(next == $%) ifTrue:[
  3807             expandedString := expandedString , '%'
  3807 	    expandedString := expandedString , '%'
  3808         ] ifFalse:[
  3808 	] ifFalse:[
  3809             (next between:$1 and:$9) ifTrue:[
  3809 	    (next between:$1 and:$9) ifTrue:[
  3810                 v := argArrayOrDictionary at:(next digitValue) ifAbsent:nil
  3810 		v := argArrayOrDictionary at:(next digitValue) ifAbsent:nil
  3811             ] ifFalse:[
  3811 	    ] ifFalse:[
  3812                 next == $( ifTrue:[
  3812 		next == $( ifTrue:[
  3813                     idx2 := self indexOf:$) startingAt:idx+2.
  3813 		    idx2 := self indexOf:$) startingAt:idx+2.
  3814                     key := self copyFrom:idx+2 to:idx2-1.
  3814 		    key := self copyFrom:idx+2 to:idx2-1.
  3815                     idx := idx2 - 1.
  3815 		    idx := idx2 - 1.
  3816                     keyAsSymbol := key asSymbolIfInterned.
  3816 		    keyAsSymbol := key asSymbolIfInterned.
  3817                     (keyAsSymbol notNil and:[ argArrayOrDictionary includesKey:keyAsSymbol ]) ifTrue:[
  3817 		    (keyAsSymbol notNil and:[ argArrayOrDictionary includesKey:keyAsSymbol ]) ifTrue:[
  3818                         v := argArrayOrDictionary at:keyAsSymbol
  3818 			v := argArrayOrDictionary at:keyAsSymbol
  3819                     ] ifFalse:[
  3819 		    ] ifFalse:[
  3820                         (key conform:[:each | each isDigit]) ifTrue:[
  3820 			(key conform:[:each | each isDigit]) ifTrue:[
  3821                             key := Number readFrom:key onError:nil.
  3821 			    key := Number readFrom:key onError:nil.
  3822                         ].
  3822 			].
  3823                         v := argArrayOrDictionary at:key ifAbsent:nil
  3823 			v := argArrayOrDictionary at:key ifAbsent:nil
  3824                     ].
  3824 		    ].
  3825                 ] ifFalse:[
  3825 		] ifFalse:[
  3826                     v := argArrayOrDictionary at:next ifAbsent:nil.
  3826 		    v := argArrayOrDictionary at:next ifAbsent:nil.
  3827                     v isNil ifTrue:[
  3827 		    v isNil ifTrue:[
  3828                         (argArrayOrDictionary includesKey:next asString) ifTrue:[
  3828 			(argArrayOrDictionary includesKey:next asString) ifTrue:[
  3829                             v := argArrayOrDictionary at:next asString asSymbol ifAbsent:nil.
  3829 			    v := argArrayOrDictionary at:next asString asSymbol ifAbsent:nil.
  3830                         ] ifFalse:[
  3830 			] ifFalse:[
  3831                             v := String with:$% with:next. "/ next asString.
  3831 			    v := String with:$% with:next. "/ next asString.
  3832                         ]
  3832 			]
  3833                     ].
  3833 		    ].
  3834                 ]
  3834 		]
  3835             ].
  3835 	    ].
  3836             v isNil 
  3836 	    v isNil
  3837                 ifTrue:[v := '']
  3837 		ifTrue:[v := '']
  3838                 ifFalse:[
  3838 		ifFalse:[
  3839                     v isBlock ifTrue:[
  3839 		    v isBlock ifTrue:[
  3840                         v := v value
  3840 			v := v value
  3841                     ]].
  3841 		    ]].
  3842             expandedString := expandedString , v printString
  3842 	    expandedString := expandedString , v printString
  3843         ].
  3843 	].
  3844         start := idx + 2
  3844 	start := idx + 2
  3845     ].
  3845     ].
  3846     ^  expandedString
  3846     ^  expandedString
  3847 
  3847 
  3848     "
  3848     "
  3849      'hello %1' expandPlaceholdersWith:#('world') 
  3849      'hello %1' expandPlaceholdersWith:#('world')
  3850      'hello %1; how is %2' expandPlaceholdersWith:#('world' 'this') 
  3850      'hello %1; how is %2' expandPlaceholdersWith:#('world' 'this')
  3851      'hello %2; how is %1' expandPlaceholdersWith:#('world' 'this') 
  3851      'hello %2; how is %1' expandPlaceholdersWith:#('world' 'this')
  3852      '%1 plus %2 gives %3 ' expandPlaceholdersWith:#(4 5 9) 
  3852      '%1 plus %2 gives %3 ' expandPlaceholdersWith:#(4 5 9)
  3853      '%%(1)0 gives %(1)0' expandPlaceholdersWith:#(123)  
  3853      '%%(1)0 gives %(1)0' expandPlaceholdersWith:#(123)
  3854      '%%10 gives %10' expandPlaceholdersWith:#(123)     
  3854      '%%10 gives %10' expandPlaceholdersWith:#(123)
  3855      '%%(10) gives %(10)' expandPlaceholdersWith:#(123) 
  3855      '%%(10) gives %(10)' expandPlaceholdersWith:#(123)
  3856     "
  3856     "
  3857 
  3857 
  3858     "
  3858     "
  3859      |dict|
  3859      |dict|
  3860 
  3860 
  3861      dict := Dictionary new.
  3861      dict := Dictionary new.
  3862      dict at:1 put:'one'.
  3862      dict at:1 put:'one'.
  3863      dict at:$a put:'AAAAA'.
  3863      dict at:$a put:'AAAAA'.
  3864      dict at:$b put:[ Time now ].
  3864      dict at:$b put:[ Time now ].
  3865      'hello %1 %a %b' expandPlaceholdersWith:dict   
  3865      'hello %1 %a %b' expandPlaceholdersWith:dict
  3866     "
  3866     "
  3867 
  3867 
  3868     "Modified: 1.7.1997 / 00:53:24 / cg"
  3868     "Modified: 1.7.1997 / 00:53:24 / cg"
  3869 !
  3869 !
  3870 
  3870 
  3884 withEscapes
  3884 withEscapes
  3885     "return a new string consisting of receivers characters
  3885     "return a new string consisting of receivers characters
  3886      with all \X-character escapes replaced by corresponding-characters.
  3886      with all \X-character escapes replaced by corresponding-characters.
  3887      (similar to the way C-language Strings are converted).
  3887      (similar to the way C-language Strings are converted).
  3888      The following escapes are supported:
  3888      The following escapes are supported:
  3889         \r      return character
  3889 	\r      return character
  3890         \n      newline character
  3890 	\n      newline character
  3891         \b      backspace character
  3891 	\b      backspace character
  3892         \f      formfeed character
  3892 	\f      formfeed character
  3893         \t      tab character
  3893 	\t      tab character
  3894         \e      escape character
  3894 	\e      escape character
  3895         \\      the \ character itself
  3895 	\\      the \ character itself
  3896         \nnn    three digit octal number defining the characters ascii value
  3896 	\nnn    three digit octal number defining the characters ascii value
  3897         \other  other
  3897 	\other  other
  3898 
  3898 
  3899      Notice, that \' is NOT a valid escape, since the general syntax of
  3899      Notice, that \' is NOT a valid escape, since the general syntax of
  3900      string constants is not affected by this method.
  3900      string constants is not affected by this method.
  3901 
  3901 
  3902      Although easily implementable, this is NOT done automatically
  3902      Although easily implementable, this is NOT done automatically
  3910     |sz      "{ SmallInteger }"
  3910     |sz      "{ SmallInteger }"
  3911      newSize "{ SmallInteger }"
  3911      newSize "{ SmallInteger }"
  3912      srcIdx  "{ SmallInteger }"
  3912      srcIdx  "{ SmallInteger }"
  3913      dstIdx  "{ SmallInteger }"
  3913      dstIdx  "{ SmallInteger }"
  3914      val     "{ SmallInteger }"
  3914      val     "{ SmallInteger }"
  3915      newString next hasEmphasis e| 
  3915      newString next hasEmphasis e|
  3916 
  3916 
  3917     "
  3917     "
  3918      first, count the number of escapes, to allow preallocation
  3918      first, count the number of escapes, to allow preallocation
  3919      of the new string ...
  3919      of the new string ...
  3920      (it is faster to scan the string twice than to reallocate it multiple
  3920      (it is faster to scan the string twice than to reallocate it multiple
  3921       times in a WriteStream)
  3921       times in a WriteStream)
  3922     "
  3922     "
  3923     sz := newSize := self size.
  3923     sz := newSize := self size.
  3924     srcIdx := 1.
  3924     srcIdx := 1.
  3925     [(srcIdx := self indexOf:$\ startingAt:srcIdx) ~~ 0] whileTrue:[
  3925     [(srcIdx := self indexOf:$\ startingAt:srcIdx) ~~ 0] whileTrue:[
  3926         srcIdx == sz ifFalse:[
  3926 	srcIdx == sz ifFalse:[
  3927             newSize := newSize - 1.
  3927 	    newSize := newSize - 1.
  3928             srcIdx := srcIdx + 1.
  3928 	    srcIdx := srcIdx + 1.
  3929             next := self at:srcIdx.
  3929 	    next := self at:srcIdx.
  3930             next == $0 ifTrue:[
  3930 	    next == $0 ifTrue:[
  3931                 [srcIdx < sz and:[next isDigit]] whileTrue:[
  3931 		[srcIdx < sz and:[next isDigit]] whileTrue:[
  3932                     newSize := newSize - 1. srcIdx := srcIdx + 1. next := self at:srcIdx.
  3932 		    newSize := newSize - 1. srcIdx := srcIdx + 1. next := self at:srcIdx.
  3933                 ]
  3933 		]
  3934             ].
  3934 	    ].
  3935         ].
  3935 	].
  3936         srcIdx := srcIdx + 1.
  3936 	srcIdx := srcIdx + 1.
  3937     ].
  3937     ].
  3938 
  3938 
  3939     newSize == sz ifTrue:[
  3939     newSize == sz ifTrue:[
  3940         ^ self
  3940 	^ self
  3941     ].
  3941     ].
  3942 
  3942 
  3943     newString := self species new:newSize.
  3943     newString := self species new:newSize.
  3944 
  3944 
  3945     hasEmphasis := self hasChangeOfEmphasis.
  3945     hasEmphasis := self hasChangeOfEmphasis.
  3947     "
  3947     "
  3948      copy over, replace escapes
  3948      copy over, replace escapes
  3949     "
  3949     "
  3950     srcIdx := dstIdx := 1.
  3950     srcIdx := dstIdx := 1.
  3951     [srcIdx <= sz] whileTrue:[
  3951     [srcIdx <= sz] whileTrue:[
  3952         next := self at:srcIdx.
  3952 	next := self at:srcIdx.
  3953         hasEmphasis ifTrue:[
  3953 	hasEmphasis ifTrue:[
  3954             e := self emphasisAt:srcIdx
  3954 	    e := self emphasisAt:srcIdx
  3955         ].
  3955 	].
  3956         srcIdx := srcIdx + 1.
  3956 	srcIdx := srcIdx + 1.
  3957         next == $\ ifTrue:[
  3957 	next == $\ ifTrue:[
  3958             srcIdx <= sz ifTrue:[
  3958 	    srcIdx <= sz ifTrue:[
  3959                 next := self at:srcIdx.
  3959 		next := self at:srcIdx.
  3960                 srcIdx := srcIdx + 1.
  3960 		srcIdx := srcIdx + 1.
  3961                 next == $r ifTrue:[
  3961 		next == $r ifTrue:[
  3962                     next := Character return
  3962 		    next := Character return
  3963                 ] ifFalse:[
  3963 		] ifFalse:[
  3964                     next == $n ifTrue:[
  3964 		    next == $n ifTrue:[
  3965                         next := Character nl
  3965 			next := Character nl
  3966                     ] ifFalse:[
  3966 		    ] ifFalse:[
  3967                         next == $b ifTrue:[
  3967 			next == $b ifTrue:[
  3968                             next := Character backspace
  3968 			    next := Character backspace
  3969                         ] ifFalse:[
  3969 			] ifFalse:[
  3970                             next == $f ifTrue:[
  3970 			    next == $f ifTrue:[
  3971                                 next := Character newPage
  3971 				next := Character newPage
  3972                             ] ifFalse:[
  3972 			    ] ifFalse:[
  3973                                 next == $t ifTrue:[
  3973 				next == $t ifTrue:[
  3974                                     next := Character tab
  3974 				    next := Character tab
  3975                                 ] ifFalse:[
  3975 				] ifFalse:[
  3976                                     next == $e ifTrue:[
  3976 				    next == $e ifTrue:[
  3977                                         next := Character esc
  3977 					next := Character esc
  3978                                     ] ifFalse:[
  3978 				    ] ifFalse:[
  3979                                         next == $0 ifTrue:[
  3979 					next == $0 ifTrue:[
  3980                                             val := 0.
  3980 					    val := 0.
  3981                                             [next notNil and:[next isDigit]] whileTrue:[
  3981 					    [next notNil and:[next isDigit]] whileTrue:[
  3982                                                 val := val * 8 + next digitValue.
  3982 						val := val * 8 + next digitValue.
  3983                                                 srcIdx <= sz ifTrue:[
  3983 						srcIdx <= sz ifTrue:[
  3984                                                     next := self at:srcIdx.
  3984 						    next := self at:srcIdx.
  3985                                                     srcIdx := srcIdx + 1.
  3985 						    srcIdx := srcIdx + 1.
  3986                                                 ] ifFalse:[
  3986 						] ifFalse:[
  3987                                                     next := nil
  3987 						    next := nil
  3988                                                 ]
  3988 						]
  3989                                             ].
  3989 					    ].
  3990                                             next := Character value:val.
  3990 					    next := Character value:val.
  3991                                         ]
  3991 					]
  3992                                     ]
  3992 				    ]
  3993                                 ]
  3993 				]
  3994                             ]
  3994 			    ]
  3995                         ]
  3995 			]
  3996                     ]
  3996 		    ]
  3997                 ].
  3997 		].
  3998             ].
  3998 	    ].
  3999         ].
  3999 	].
  4000         newString at:dstIdx put:next.
  4000 	newString at:dstIdx put:next.
  4001         hasEmphasis ifTrue:[
  4001 	hasEmphasis ifTrue:[
  4002             newString emphasisAt:dstIdx put:e
  4002 	    newString emphasisAt:dstIdx put:e
  4003         ].
  4003 	].
  4004         dstIdx := dstIdx + 1.
  4004 	dstIdx := dstIdx + 1.
  4005     ].
  4005     ].
  4006     ^ newString
  4006     ^ newString
  4007 
  4007 
  4008     "
  4008     "
  4009      'hello world' withEscapes  
  4009      'hello world' withEscapes
  4010      'hello\world' withEscapes   
  4010      'hello\world' withEscapes
  4011      'hello\world\' withEscapes   
  4011      'hello\world\' withEscapes
  4012      'hello world\' withEscapes   
  4012      'hello world\' withEscapes
  4013      'hello\tworld' withEscapes   
  4013      'hello\tworld' withEscapes
  4014      'hello\nworld\na\n\tnice\n\t\tstring' withEscapes   
  4014      'hello\nworld\na\n\tnice\n\t\tstring' withEscapes
  4015      'hello\tworld\n' withEscapes   
  4015      'hello\tworld\n' withEscapes
  4016      'hello\010world' withEscapes   
  4016      'hello\010world' withEscapes
  4017      'hello\r\nworld' withEscapes   
  4017      'hello\r\nworld' withEscapes
  4018     "
  4018     "
  4019 
  4019 
  4020     "Modified: 12.5.1996 / 12:53:34 / cg"
  4020     "Modified: 12.5.1996 / 12:53:34 / cg"
  4021 !
  4021 !
  4022 
  4022 
  4030     escape := self class matchEscapeCharacter.
  4030     escape := self class matchEscapeCharacter.
  4031 
  4031 
  4032     in := self readStream.
  4032     in := self readStream.
  4033     out := WriteStream on:(self species new:self size).
  4033     out := WriteStream on:(self species new:self size).
  4034     [in atEnd] whileFalse:[
  4034     [in atEnd] whileFalse:[
  4035         c := in next.
  4035 	c := in next.
  4036         (c == escape or:['*[#' includes:c]) ifTrue:[
  4036 	(c == escape or:['*[#' includes:c]) ifTrue:[
  4037             out nextPut:$\.
  4037 	    out nextPut:$\.
  4038         ].
  4038 	].
  4039         out nextPut:c.
  4039 	out nextPut:c.
  4040     ].
  4040     ].
  4041     ^ out contents.
  4041     ^ out contents.
  4042 
  4042 
  4043     "
  4043     "
  4044      '*foo' withMatchEscapes   
  4044      '*foo' withMatchEscapes
  4045      '\*foo' withMatchEscapes  
  4045      '\*foo' withMatchEscapes
  4046      '*foo' withMatchEscapes   
  4046      '*foo' withMatchEscapes
  4047      '\\*foo' withMatchEscapes 
  4047      '\\*foo' withMatchEscapes
  4048      'foo*' withMatchEscapes   
  4048      'foo*' withMatchEscapes
  4049      'foo\*' withMatchEscapes  
  4049      'foo\*' withMatchEscapes
  4050      'foo\' withMatchEscapes  
  4050      'foo\' withMatchEscapes
  4051      'f*o*o' withMatchEscapes   
  4051      'f*o*o' withMatchEscapes
  4052     "
  4052     "
  4053 
  4053 
  4054     "Modified: 2.4.1997 / 18:13:04 / cg"
  4054     "Modified: 2.4.1997 / 18:13:04 / cg"
  4055 !
  4055 !
  4056 
  4056 
  4057 withTabs
  4057 withTabs
  4058     "return a string consisting of the receivers characters
  4058     "return a string consisting of the receivers characters
  4059      where leading spaces are replaced by tabulator characters (assuming 8-col tabs).
  4059      where leading spaces are replaced by tabulator characters (assuming 8-col tabs).
  4060      Notice: if the receiver does not contain any tabs, it is returned unchanged;
  4060      Notice: if the receiver does not contain any tabs, it is returned unchanged;
  4061      otherwise a new string is returned.
  4061      otherwise a new string is returned.
  4062      Limitation: only the very first spaces are replaced 
  4062      Limitation: only the very first spaces are replaced
  4063                  (i.e. if the receiver contains newLine characters,
  4063 		 (i.e. if the receiver contains newLine characters,
  4064                   no tabs are inserted after those lineBreaks)"
  4064 		  no tabs are inserted after those lineBreaks)"
  4065 
  4065 
  4066     |idx   "{ SmallInteger }" 
  4066     |idx   "{ SmallInteger }"
  4067      nTabs "{ SmallInteger }" 
  4067      nTabs "{ SmallInteger }"
  4068      newString|
  4068      newString|
  4069 
  4069 
  4070     idx := self findFirst:[:c | (c ~~ Character space)].
  4070     idx := self findFirst:[:c | (c ~~ Character space)].
  4071     nTabs := (idx-1) // 8.
  4071     nTabs := (idx-1) // 8.
  4072     nTabs <= 0 ifTrue:[^ self].
  4072     nTabs <= 0 ifTrue:[^ self].
  4076     newString atAll:(1 to:nTabs) put:(Character tab).
  4076     newString atAll:(1 to:nTabs) put:(Character tab).
  4077     newString replaceFrom:(nTabs + 1) with:self startingAt:(nTabs * 8 + 1).
  4077     newString replaceFrom:(nTabs + 1) with:self startingAt:(nTabs * 8 + 1).
  4078     ^ newString
  4078     ^ newString
  4079 
  4079 
  4080     "
  4080     "
  4081      '12345678901234567890' withTabs 
  4081      '12345678901234567890' withTabs
  4082      '       8901234567890' withTabs 
  4082      '       8901234567890' withTabs
  4083      '        901234567890' withTabs  
  4083      '        901234567890' withTabs
  4084      '               67890' withTabs
  4084      '               67890' withTabs
  4085      '                7890' withTabs
  4085      '                7890' withTabs
  4086      '                 890' withTabs
  4086      '                 890' withTabs
  4087     "
  4087     "
  4088 !
  4088 !
  4089 
  4089 
  4090 withTabsExpanded
  4090 withTabsExpanded
  4091     "return a string consisting of the receivers characters,
  4091     "return a string consisting of the receivers characters,
  4092      where all tabulator characters are expanded into spaces (assuming 8-col tabs). 
  4092      where all tabulator characters are expanded into spaces (assuming 8-col tabs).
  4093      Notice: if the receiver does not contain any tabs, it is returned unchanged;
  4093      Notice: if the receiver does not contain any tabs, it is returned unchanged;
  4094      otherwise a new string is returned.
  4094      otherwise a new string is returned.
  4095      This does handle multiline strings."
  4095      This does handle multiline strings."
  4096 
  4096 
  4097     ^ self withTabsExpanded:8
  4097     ^ self withTabsExpanded:8
  4098 
  4098 
  4099     "
  4099     "
  4100      ('1' , Character tab asString , 'x') withTabsExpanded          
  4100      ('1' , Character tab asString , 'x') withTabsExpanded
  4101      ('12345' , Character tab asString , 'x') withTabsExpanded      
  4101      ('12345' , Character tab asString , 'x') withTabsExpanded
  4102      ('123456' , Character tab asString , 'x') withTabsExpanded     
  4102      ('123456' , Character tab asString , 'x') withTabsExpanded
  4103      ('1234567' , Character tab asString , 'x') withTabsExpanded   
  4103      ('1234567' , Character tab asString , 'x') withTabsExpanded
  4104      ('12345678' , Character tab asString , 'x') withTabsExpanded   
  4104      ('12345678' , Character tab asString , 'x') withTabsExpanded
  4105      ('123456789' , Character tab asString , 'x') withTabsExpanded 
  4105      ('123456789' , Character tab asString , 'x') withTabsExpanded
  4106 
  4106 
  4107      (String with:Character tab
  4107      (String with:Character tab
  4108              with:Character tab
  4108 	     with:Character tab
  4109              with:$1) withTabsExpanded
  4109 	     with:$1) withTabsExpanded
  4110 
  4110 
  4111      (String with:Character tab
  4111      (String with:Character tab
  4112              with:$1
  4112 	     with:$1
  4113              with:Character tab
  4113 	     with:Character tab
  4114              with:$2) withTabsExpanded  
  4114 	     with:$2) withTabsExpanded
  4115 
  4115 
  4116      (String with:Character tab
  4116      (String with:Character tab
  4117              with:$1
  4117 	     with:$1
  4118              with:Character cr
  4118 	     with:Character cr
  4119              with:Character tab
  4119 	     with:Character tab
  4120              with:$2) withTabsExpanded  
  4120 	     with:$2) withTabsExpanded
  4121     "
  4121     "
  4122 
  4122 
  4123     "Modified: 12.5.1996 / 13:05:10 / cg"
  4123     "Modified: 12.5.1996 / 13:05:10 / cg"
  4124 !
  4124 !
  4125 
  4125 
  4126 withTabsExpanded:numSpaces
  4126 withTabsExpanded:numSpaces
  4127     "return a string consisting of the receivers characters,
  4127     "return a string consisting of the receivers characters,
  4128      where all tabulator characters are expanded into spaces (assuming numSpaces-col tabs). 
  4128      where all tabulator characters are expanded into spaces (assuming numSpaces-col tabs).
  4129      Notice: if the receiver does not contain any tabs, it is returned unchanged;
  4129      Notice: if the receiver does not contain any tabs, it is returned unchanged;
  4130      otherwise a new string is returned.
  4130      otherwise a new string is returned.
  4131      This does handle multiline strings."
  4131      This does handle multiline strings."
  4132 
  4132 
  4133     |col    "{ SmallInteger }" 
  4133     |col    "{ SmallInteger }"
  4134      str ch
  4134      str ch
  4135      dstIdx "{ SmallInteger }"
  4135      dstIdx "{ SmallInteger }"
  4136      newSz  "{ SmallInteger }"
  4136      newSz  "{ SmallInteger }"
  4137      sz "{ SmallInteger }"
  4137      sz "{ SmallInteger }"
  4138      hasEmphasis e|
  4138      hasEmphasis e|
  4144     "/ count the new size first, instead of
  4144     "/ count the new size first, instead of
  4145     "/ multiple resizing (better for large strings)
  4145     "/ multiple resizing (better for large strings)
  4146 
  4146 
  4147     col := 1. newSz := 0.
  4147     col := 1. newSz := 0.
  4148     1 to:sz do:[:srcIdx |
  4148     1 to:sz do:[:srcIdx |
  4149         ch := self at:srcIdx.
  4149 	ch := self at:srcIdx.
  4150         ch == Character tab ifFalse:[
  4150 	ch == Character tab ifFalse:[
  4151             col := col + 1.
  4151 	    col := col + 1.
  4152             newSz := newSz + 1.
  4152 	    newSz := newSz + 1.
  4153             ch == Character cr ifTrue:[
  4153 	    ch == Character cr ifTrue:[
  4154                 col := 1
  4154 		col := 1
  4155             ].
  4155 	    ].
  4156         ] ifTrue:[
  4156 	] ifTrue:[
  4157             (col \\ numSpaces) to:numSpaces do:[:ii |
  4157 	    (col \\ numSpaces) to:numSpaces do:[:ii |
  4158                 newSz := newSz + 1.
  4158 		newSz := newSz + 1.
  4159                 col := col + 1
  4159 		col := col + 1
  4160             ].
  4160 	    ].
  4161         ]
  4161 	]
  4162     ].
  4162     ].
  4163 
  4163 
  4164     str := self species new:newSz.
  4164     str := self species new:newSz.
  4165 
  4165 
  4166     hasEmphasis := self hasChangeOfEmphasis.
  4166     hasEmphasis := self hasChangeOfEmphasis.
  4167 
  4167 
  4168     col := 1. dstIdx := 1.
  4168     col := 1. dstIdx := 1.
  4169     1 to:sz do:[:srcIdx |
  4169     1 to:sz do:[:srcIdx |
  4170         ch := self at:srcIdx.
  4170 	ch := self at:srcIdx.
  4171 
  4171 
  4172         ch == Character tab ifFalse:[
  4172 	ch == Character tab ifFalse:[
  4173             col := col + 1.
  4173 	    col := col + 1.
  4174             ch == Character cr ifTrue:[
  4174 	    ch == Character cr ifTrue:[
  4175                 col := 1
  4175 		col := 1
  4176             ].
  4176 	    ].
  4177             hasEmphasis ifTrue:[
  4177 	    hasEmphasis ifTrue:[
  4178                 e := self emphasisAt:srcIdx.
  4178 		e := self emphasisAt:srcIdx.
  4179                 str emphasisAt:dstIdx put:e
  4179 		str emphasisAt:dstIdx put:e
  4180             ].
  4180 	    ].
  4181             str at:dstIdx put:ch.
  4181 	    str at:dstIdx put:ch.
  4182             dstIdx := dstIdx + 1
  4182 	    dstIdx := dstIdx + 1
  4183         ] ifTrue:[
  4183 	] ifTrue:[
  4184             (col \\ numSpaces) to:numSpaces do:[:ii |
  4184 	    (col \\ numSpaces) to:numSpaces do:[:ii |
  4185                 str at:dstIdx put:Character space.
  4185 		str at:dstIdx put:Character space.
  4186                 dstIdx := dstIdx + 1.
  4186 		dstIdx := dstIdx + 1.
  4187                 col := col + 1
  4187 		col := col + 1
  4188             ].
  4188 	    ].
  4189         ]
  4189 	]
  4190     ].
  4190     ].
  4191     ^ str
  4191     ^ str
  4192 
  4192 
  4193     "
  4193     "
  4194      ('1' , Character tab asString , 'x') withTabsExpanded          
  4194      ('1' , Character tab asString , 'x') withTabsExpanded
  4195      ('1' , Character tab asString , 'x') withTabsExpanded:4          
  4195      ('1' , Character tab asString , 'x') withTabsExpanded:4
  4196      ('12345' , Character tab asString , 'x') withTabsExpanded      
  4196      ('12345' , Character tab asString , 'x') withTabsExpanded
  4197      ('123456' , Character tab asString , 'x') withTabsExpanded     
  4197      ('123456' , Character tab asString , 'x') withTabsExpanded
  4198      ('1234567' , Character tab asString , 'x') withTabsExpanded   
  4198      ('1234567' , Character tab asString , 'x') withTabsExpanded
  4199      ('12345678' , Character tab asString , 'x') withTabsExpanded   
  4199      ('12345678' , Character tab asString , 'x') withTabsExpanded
  4200      ('123456789' , Character tab asString , 'x') withTabsExpanded 
  4200      ('123456789' , Character tab asString , 'x') withTabsExpanded
  4201 
  4201 
  4202      (String with:Character tab
  4202      (String with:Character tab
  4203              with:Character tab
  4203 	     with:Character tab
  4204              with:$1) withTabsExpanded
  4204 	     with:$1) withTabsExpanded
  4205 
  4205 
  4206      (String with:Character tab
  4206      (String with:Character tab
  4207              with:$1
  4207 	     with:$1
  4208              with:Character tab
  4208 	     with:Character tab
  4209              with:$2) withTabsExpanded  
  4209 	     with:$2) withTabsExpanded
  4210 
  4210 
  4211      (String with:Character tab
  4211      (String with:Character tab
  4212              with:$1
  4212 	     with:$1
  4213              with:Character cr
  4213 	     with:Character cr
  4214              with:Character tab
  4214 	     with:Character tab
  4215              with:$2) withTabsExpanded  
  4215 	     with:$2) withTabsExpanded
  4216     "
  4216     "
  4217 
  4217 
  4218     "Modified: 12.5.1996 / 13:05:10 / cg"
  4218     "Modified: 12.5.1996 / 13:05:10 / cg"
  4219 !
  4219 !
  4220 
  4220 
  4247 	^ self copyFrom:index
  4247 	^ self copyFrom:index
  4248     ].
  4248     ].
  4249     ^ ''
  4249     ^ ''
  4250 
  4250 
  4251     "
  4251     "
  4252      '    foo    ' withoutLeadingSeparators  
  4252      '    foo    ' withoutLeadingSeparators
  4253      'foo    '     withoutLeadingSeparators   
  4253      'foo    '     withoutLeadingSeparators
  4254      '    foo'     withoutLeadingSeparators  
  4254      '    foo'     withoutLeadingSeparators
  4255      '       '     withoutLeadingSeparators   
  4255      '       '     withoutLeadingSeparators
  4256      'foo'         withoutLeadingSeparators   
  4256      'foo'         withoutLeadingSeparators
  4257      ('  ' , Character tab asString , ' foo   ') withoutLeadingSeparators inspect 
  4257      ('  ' , Character tab asString , ' foo   ') withoutLeadingSeparators inspect
  4258     "
  4258     "
  4259 !
  4259 !
  4260 
  4260 
  4261 withoutMatchEscapes
  4261 withoutMatchEscapes
  4262     "return a copy of the receiver with all $\ removed or
  4262     "return a copy of the receiver with all $\ removed or
  4267     escape := self class matchEscapeCharacter.
  4267     escape := self class matchEscapeCharacter.
  4268 
  4268 
  4269     in := self readStream.
  4269     in := self readStream.
  4270     out := self species writeStream.
  4270     out := self species writeStream.
  4271     [in atEnd] whileFalse:[
  4271     [in atEnd] whileFalse:[
  4272         c := in next.
  4272 	c := in next.
  4273         c == escape ifTrue:[
  4273 	c == escape ifTrue:[
  4274             in atEnd ifFalse:[
  4274 	    in atEnd ifFalse:[
  4275                 c := in next.
  4275 		c := in next.
  4276             ]
  4276 	    ]
  4277         ].
  4277 	].
  4278         out nextPut:c.
  4278 	out nextPut:c.
  4279     ].
  4279     ].
  4280     ^ out contents.
  4280     ^ out contents.
  4281 
  4281 
  4282     "
  4282     "
  4283      '*foo' withoutMatchEscapes   
  4283      '*foo' withoutMatchEscapes
  4284      '\*foo' withoutMatchEscapes  
  4284      '\*foo' withoutMatchEscapes
  4285      '*foo' withoutMatchEscapes   
  4285      '*foo' withoutMatchEscapes
  4286      '\\*foo' withoutMatchEscapes 
  4286      '\\*foo' withoutMatchEscapes
  4287      'foo*' withoutMatchEscapes   
  4287      'foo*' withoutMatchEscapes
  4288      'foo\*' withoutMatchEscapes  
  4288      'foo\*' withoutMatchEscapes
  4289      'foo\' withoutMatchEscapes  
  4289      'foo\' withoutMatchEscapes
  4290      'f\*o\*o' withoutMatchEscapes   
  4290      'f\*o\*o' withoutMatchEscapes
  4291     "
  4291     "
  4292 
  4292 
  4293     "Modified: 30.6.1997 / 13:40:23 / cg"
  4293     "Modified: 30.6.1997 / 13:40:23 / cg"
  4294 !
  4294 !
  4295 
  4295 
  4296 withoutPrefix:aString
  4296 withoutPrefix:aString
  4297     "if the receiver startsWith aPrefix, return a copy without it.
  4297     "if the receiver startsWith aPrefix, return a copy without it.
  4298      Otherwise return the receiver"
  4298      Otherwise return the receiver"
  4299 
  4299 
  4300     (self startsWith:aString) ifTrue:[
  4300     (self startsWith:aString) ifTrue:[
  4301         ^ self copyFrom:aString size + 1
  4301 	^ self copyFrom:aString size + 1
  4302     ].
  4302     ].
  4303     ^ self
  4303     ^ self
  4304 
  4304 
  4305     "
  4305     "
  4306      'helloworld' withoutPrefix:'hello'
  4306      'helloworld' withoutPrefix:'hello'
  4313      (but whiteSpace in-between is preserved)
  4313      (but whiteSpace in-between is preserved)
  4314      Whitespace is space, tab, newline, formfeed.
  4314      Whitespace is space, tab, newline, formfeed.
  4315      Use withoutSpaces, if you want to remove spaces only."
  4315      Use withoutSpaces, if you want to remove spaces only."
  4316 
  4316 
  4317     |startIndex "{ Class: SmallInteger }"
  4317     |startIndex "{ Class: SmallInteger }"
  4318      endIndex   "{ Class: SmallInteger }" 
  4318      endIndex   "{ Class: SmallInteger }"
  4319      sz|
  4319      sz|
  4320 
  4320 
  4321     sz := self size.
  4321     sz := self size.
  4322     startIndex := 1.
  4322     startIndex := 1.
  4323     endIndex := sz.
  4323     endIndex := sz.
  4324 
  4324 
  4325     [(startIndex < endIndex) and:[(self at:startIndex) isSeparator]] whileTrue:[
  4325     [(startIndex < endIndex) and:[(self at:startIndex) isSeparator]] whileTrue:[
  4326         startIndex := startIndex + 1
  4326 	startIndex := startIndex + 1
  4327     ].
  4327     ].
  4328     [(endIndex > 1) and:[(self at:endIndex) isSeparator]] whileTrue:[
  4328     [(endIndex > 1) and:[(self at:endIndex) isSeparator]] whileTrue:[
  4329         endIndex := endIndex - 1
  4329 	endIndex := endIndex - 1
  4330     ].
  4330     ].
  4331     startIndex > endIndex ifTrue:[
  4331     startIndex > endIndex ifTrue:[
  4332         ^ ''
  4332 	^ ''
  4333     ].
  4333     ].
  4334     ((startIndex == 1) and:[endIndex == sz]) ifTrue:[
  4334     ((startIndex == 1) and:[endIndex == sz]) ifTrue:[
  4335         ^ self
  4335 	^ self
  4336     ].
  4336     ].
  4337     ^ self copyFrom:startIndex to:endIndex
  4337     ^ self copyFrom:startIndex to:endIndex
  4338 
  4338 
  4339     "
  4339     "
  4340      '    foo    ' withoutSeparators      
  4340      '    foo    ' withoutSeparators
  4341      '    foo' withoutSeparators      
  4341      '    foo' withoutSeparators
  4342      'foo    ' withoutSeparators      
  4342      'foo    ' withoutSeparators
  4343      '       ' withoutSeparators      
  4343      '       ' withoutSeparators
  4344      ('  foo' , Character tab asString , '    ') withoutSeparators inspect 
  4344      ('  foo' , Character tab asString , '    ') withoutSeparators inspect
  4345     "
  4345     "
  4346 !
  4346 !
  4347 
  4347 
  4348 withoutSpaces
  4348 withoutSpaces
  4349     "return a copy of myself without leading and trailing spaces.
  4349     "return a copy of myself without leading and trailing spaces.
  4350      (but spaces in-between are preserved)
  4350      (but spaces in-between are preserved)
  4351      Notice: this does NOT remove tabs, newline or any other whitespace.
  4351      Notice: this does NOT remove tabs, newline or any other whitespace.
  4352      Use withoutSeparators for this."
  4352      Use withoutSeparators for this."
  4353 
  4353 
  4354     |startIndex "{ Class: SmallInteger }"
  4354     |startIndex "{ Class: SmallInteger }"
  4355      endIndex   "{ Class: SmallInteger }" 
  4355      endIndex   "{ Class: SmallInteger }"
  4356      sz|
  4356      sz|
  4357 
  4357 
  4358     sz := self size.
  4358     sz := self size.
  4359     startIndex := 1.
  4359     startIndex := 1.
  4360     endIndex := sz.
  4360     endIndex := sz.
  4361 
  4361 
  4362     [(startIndex < endIndex) and:[(self at:startIndex) == Character space]] whileTrue:[
  4362     [(startIndex < endIndex) and:[(self at:startIndex) == Character space]] whileTrue:[
  4363         startIndex := startIndex + 1
  4363 	startIndex := startIndex + 1
  4364     ].
  4364     ].
  4365     [(endIndex > 1) and:[(self at:endIndex) == Character space]] whileTrue:[
  4365     [(endIndex > 1) and:[(self at:endIndex) == Character space]] whileTrue:[
  4366         endIndex := endIndex - 1
  4366 	endIndex := endIndex - 1
  4367     ].
  4367     ].
  4368     startIndex > endIndex ifTrue:[
  4368     startIndex > endIndex ifTrue:[
  4369         ^ ''
  4369 	^ ''
  4370     ].
  4370     ].
  4371     ((startIndex == 1) and:[endIndex == sz]) ifTrue:[
  4371     ((startIndex == 1) and:[endIndex == sz]) ifTrue:[
  4372         ^ self
  4372 	^ self
  4373     ].
  4373     ].
  4374     ^ self copyFrom:startIndex to:endIndex
  4374     ^ self copyFrom:startIndex to:endIndex
  4375 
  4375 
  4376     "
  4376     "
  4377      '    foo    ' withoutSpaces  
  4377      '    foo    ' withoutSpaces
  4378      'foo    '     withoutSpaces   
  4378      'foo    '     withoutSpaces
  4379      '    foo'     withoutSpaces  
  4379      '    foo'     withoutSpaces
  4380      '       '     withoutSpaces   
  4380      '       '     withoutSpaces
  4381      'a     b'     withoutSpaces   
  4381      'a     b'     withoutSpaces
  4382      ('  foo' , Character tab asString , '    ') withoutSpaces inspect 
  4382      ('  foo' , Character tab asString , '    ') withoutSpaces inspect
  4383     "
  4383     "
  4384 !
  4384 !
  4385 
  4385 
  4386 withoutTrailingSeparators
  4386 withoutTrailingSeparators
  4387     "return a copy of myself without trailing separators.
  4387     "return a copy of myself without trailing separators.
  4398 	index := index - 1
  4398 	index := index - 1
  4399     ].
  4399     ].
  4400     ^ ''
  4400     ^ ''
  4401 
  4401 
  4402     "
  4402     "
  4403      '    foo    ' withoutTrailingSeparators  
  4403      '    foo    ' withoutTrailingSeparators
  4404      'foo    '     withoutTrailingSeparators   
  4404      'foo    '     withoutTrailingSeparators
  4405      '    foo'     withoutTrailingSeparators  
  4405      '    foo'     withoutTrailingSeparators
  4406      '       '     withoutTrailingSeparators   
  4406      '       '     withoutTrailingSeparators
  4407      'foo'         withoutTrailingSeparators   
  4407      'foo'         withoutTrailingSeparators
  4408      ('  ' , Character tab asString , ' foo   ') withoutTrailingSeparators inspect 
  4408      ('  ' , Character tab asString , ' foo   ') withoutTrailingSeparators inspect
  4409      ('   foo' , Character tab asString) withoutTrailingSeparators inspect 
  4409      ('   foo' , Character tab asString) withoutTrailingSeparators inspect
  4410     "
  4410     "
  4411 ! !
  4411 ! !
  4412 
  4412 
  4413 !CharacterArray methodsFor:'substring searching'!
  4413 !CharacterArray methodsFor:'substring searching'!
  4414 
  4414 
  4417      if not found, return 0."
  4417      if not found, return 0."
  4418 
  4418 
  4419     ^ self indexOfSubCollection:subString startingAt:1 ifAbsent:0
  4419     ^ self indexOfSubCollection:subString startingAt:1 ifAbsent:0
  4420 
  4420 
  4421     "
  4421     "
  4422      'hello world' findString:'llo'   
  4422      'hello world' findString:'llo'
  4423      'hello world' findString:'ole'  
  4423      'hello world' findString:'ole'
  4424     "
  4424     "
  4425 !
  4425 !
  4426 
  4426 
  4427 findString:subString ifAbsent:exceptionBlock
  4427 findString:subString ifAbsent:exceptionBlock
  4428     "find a substring. If found, return the index;
  4428     "find a substring. If found, return the index;
  4436      if not found, return 0."
  4436      if not found, return 0."
  4437 
  4437 
  4438     ^ self indexOfSubCollection:subString startingAt:index ifAbsent:0
  4438     ^ self indexOfSubCollection:subString startingAt:index ifAbsent:0
  4439 
  4439 
  4440     "
  4440     "
  4441      'hello yello' findString:'llo' startingAt:1   
  4441      'hello yello' findString:'llo' startingAt:1
  4442      'hello yello' findString:'llo' startingAt:5   
  4442      'hello yello' findString:'llo' startingAt:5
  4443      'hello yello' findString:'llo' startingAt:15   
  4443      'hello yello' findString:'llo' startingAt:15
  4444     "
  4444     "
  4445 !
  4445 !
  4446 
  4446 
  4447 findString:subString startingAt:index ifAbsent:exceptionBlock
  4447 findString:subString startingAt:index ifAbsent:exceptionBlock
  4448     "find a substring, starting at index. if found, return the index;
  4448     "find a substring, starting at index. if found, return the index;
  4455     "return true, if a substring is contained in the receiver"
  4455     "return true, if a substring is contained in the receiver"
  4456 
  4456 
  4457     ^ (self indexOfSubCollection:aString startingAt:1 ifAbsent:0) ~~ 0
  4457     ^ (self indexOfSubCollection:aString startingAt:1 ifAbsent:0) ~~ 0
  4458 
  4458 
  4459     "
  4459     "
  4460      'hello world' includesString:'hel' 
  4460      'hello world' includesString:'hel'
  4461      'hello world' includesString:'rld' 
  4461      'hello world' includesString:'rld'
  4462      'hello world' includesString:'llo'  
  4462      'hello world' includesString:'llo'
  4463      'hello world' includesString:'LLO'   
  4463      'hello world' includesString:'LLO'
  4464     "
  4464     "
  4465 !
  4465 !
  4466 
  4466 
  4467 indexOfSubCollection:subString startingAt:index ifAbsent:exceptionBlock
  4467 indexOfSubCollection:subString startingAt:index ifAbsent:exceptionBlock
  4468     "find a substring, starting at index. if found, return the index;
  4468     "find a substring, starting at index. if found, return the index;
  4475      mySize     "{ Class: SmallInteger }"
  4475      mySize     "{ Class: SmallInteger }"
  4476      runIdx     "{ Class: SmallInteger }" |
  4476      runIdx     "{ Class: SmallInteger }" |
  4477 
  4477 
  4478     subSize := subString size.
  4478     subSize := subString size.
  4479     subSize == 0 ifTrue:[   "empty string matches"
  4479     subSize == 0 ifTrue:[   "empty string matches"
  4480         subString isString ifFalse:[
  4480 	subString isString ifFalse:[
  4481            self error:'non string argument' mayProceed:true.
  4481 	   self error:'non string argument' mayProceed:true.
  4482         ].
  4482 	].
  4483         ^ index
  4483 	^ index
  4484     ].
  4484     ].
  4485     mySize := self size.
  4485     mySize := self size.
  4486     firstChar := subString at:1.
  4486     firstChar := subString at:1.
  4487     startIndex := self indexOf:firstChar startingAt:index.
  4487     startIndex := self indexOf:firstChar startingAt:index.
  4488     [startIndex == 0] whileFalse:[
  4488     [startIndex == 0] whileFalse:[
  4489         runIdx := startIndex.
  4489 	runIdx := startIndex.
  4490         found := true.
  4490 	found := true.
  4491         1 to:subSize do:[:i |
  4491 	1 to:subSize do:[:i |
  4492             runIdx > mySize ifTrue:[
  4492 	    runIdx > mySize ifTrue:[
  4493                 found := false
  4493 		found := false
  4494             ] ifFalse:[
  4494 	    ] ifFalse:[
  4495                 (subString at:i) ~= (self at:runIdx) ifTrue:[
  4495 		(subString at:i) ~= (self at:runIdx) ifTrue:[
  4496                     found := false
  4496 		    found := false
  4497                 ]
  4497 		]
  4498             ].
  4498 	    ].
  4499             runIdx := runIdx + 1
  4499 	    runIdx := runIdx + 1
  4500         ].
  4500 	].
  4501         found ifTrue:[
  4501 	found ifTrue:[
  4502             ^ startIndex
  4502 	    ^ startIndex
  4503         ].
  4503 	].
  4504         startIndex := self indexOf:firstChar startingAt:(startIndex + 1)
  4504 	startIndex := self indexOf:firstChar startingAt:(startIndex + 1)
  4505     ].
  4505     ].
  4506     ^ exceptionBlock value
  4506     ^ exceptionBlock value
  4507 
  4507 
  4508     "Modified: 23.2.1996 / 15:35:15 / cg"
  4508     "Modified: 23.2.1996 / 15:35:15 / cg"
  4509 !
  4509 !
  4510 
  4510 
  4511 restAfter:keyword withoutSeparators:strip
  4511 restAfter:keyword withoutSeparators:strip
  4512     "compare the left of the receiver with keyword,
  4512     "compare the left of the receiver with keyword,
  4513      if it matches return the right. 
  4513      if it matches return the right.
  4514      Finally, if strip is true, remove whiteSpace.
  4514      Finally, if strip is true, remove whiteSpace.
  4515      This method is used to match and extract lines of the form:
  4515      This method is used to match and extract lines of the form:
  4516 	something: rest
  4516 	something: rest
  4517      where we are interested in rest, but only if the receiver string
  4517      where we are interested in rest, but only if the receiver string
  4518      begins with something. 
  4518      begins with something.
  4519 
  4519 
  4520      You may wonder why such a specialized method exists here
  4520      You may wonder why such a specialized method exists here
  4521      - this is so common when processing mailboxes,
  4521      - this is so common when processing mailboxes,
  4522      rcs files, nntp/pop3 responses, that is was considered worth
  4522      rcs files, nntp/pop3 responses, that is was considered worth
  4523      a special method here to avoid having the code below a hundred
  4523      a special method here to avoid having the code below a hundred
  4533 	^ rest
  4533 	^ rest
  4534     ].
  4534     ].
  4535     ^ nil
  4535     ^ nil
  4536 
  4536 
  4537     "
  4537     "
  4538      'foo: hello world' restAfter:'foo:' withoutSeparators:true 
  4538      'foo: hello world' restAfter:'foo:' withoutSeparators:true
  4539      'funny: something' restAfter:'foo:' withoutSeparators:true 
  4539      'funny: something' restAfter:'foo:' withoutSeparators:true
  4540 
  4540 
  4541      'foo:     hello world    ' restAfter:'foo:' withoutSeparators:true 
  4541      'foo:     hello world    ' restAfter:'foo:' withoutSeparators:true
  4542      'foo:     hello world    ' restAfter:'foo:' withoutSeparators:false 
  4542      'foo:     hello world    ' restAfter:'foo:' withoutSeparators:false
  4543     "
  4543     "
  4544 
  4544 
  4545     "Created: 25.11.1995 / 11:04:18 / cg"
  4545     "Created: 25.11.1995 / 11:04:18 / cg"
  4546 ! !
  4546 ! !
  4547 
  4547 
  4556 
  4556 
  4557     sz := aString size.
  4557     sz := aString size.
  4558     idx := startIndex.
  4558     idx := startIndex.
  4559 
  4559 
  4560     1 to:sz do:[:i |
  4560     1 to:sz do:[:i |
  4561         (self at:idx) ~~ (aString at:i) ifTrue:[^ false].
  4561 	(self at:idx) ~~ (aString at:i) ifTrue:[^ false].
  4562         idx := idx + 1
  4562 	idx := idx + 1
  4563     ].
  4563     ].
  4564     ^ true
  4564     ^ true
  4565 
  4565 
  4566     "
  4566     "
  4567      'hello world' continuesWith:'world' startingAt:6                
  4567      'hello world' continuesWith:'world' startingAt:6
  4568      'hello world' continuesWith:'world' startingAt:7                
  4568      'hello world' continuesWith:'world' startingAt:7
  4569     "
  4569     "
  4570 
  4570 
  4571     "Created: 12.5.1996 / 15:46:40 / cg"
  4571     "Created: 12.5.1996 / 15:46:40 / cg"
  4572     "Modified: 26.7.1996 / 19:08:36 / cg"
  4572     "Modified: 26.7.1996 / 19:08:36 / cg"
  4573 !
  4573 !
  4607     "return true, if the receiver ends with something, aStringOrCharacter."
  4607     "return true, if the receiver ends with something, aStringOrCharacter."
  4608 
  4608 
  4609     |s|
  4609     |s|
  4610 
  4610 
  4611     (s := self string) ~~ self ifTrue:[
  4611     (s := self string) ~~ self ifTrue:[
  4612         ^ s endsWith:aStringOrCharacter
  4612 	^ s endsWith:aStringOrCharacter
  4613     ].
  4613     ].
  4614     aStringOrCharacter isCharacter ifTrue:[
  4614     aStringOrCharacter isCharacter ifTrue:[
  4615         ^ self last = aStringOrCharacter
  4615 	^ self last = aStringOrCharacter
  4616     ].
  4616     ].
  4617     ^ super endsWith:aStringOrCharacter
  4617     ^ super endsWith:aStringOrCharacter
  4618 
  4618 
  4619     "
  4619     "
  4620      'hello world' endsWith:'world'                 
  4620      'hello world' endsWith:'world'
  4621      'hello world' asText allBold endsWith:'world'  
  4621      'hello world' asText allBold endsWith:'world'
  4622     "
  4622     "
  4623 
  4623 
  4624     "Modified: 12.5.1996 / 15:49:18 / cg"
  4624     "Modified: 12.5.1996 / 15:49:18 / cg"
  4625 !
  4625 !
  4626 
  4626 
  4637 	char isLetterOrDigit ifFalse:[^ false].
  4637 	char isLetterOrDigit ifFalse:[^ false].
  4638     ].
  4638     ].
  4639     ^ true
  4639     ^ true
  4640 
  4640 
  4641     "
  4641     "
  4642      'helloWorld' isAlphaNumeric  
  4642      'helloWorld' isAlphaNumeric
  4643      'foo1234' isAlphaNumeric    
  4643      'foo1234' isAlphaNumeric
  4644      'f1234' isAlphaNumeric      
  4644      'f1234' isAlphaNumeric
  4645      '1234' isAlphaNumeric       
  4645      '1234' isAlphaNumeric
  4646      '+' isAlphaNumeric         
  4646      '+' isAlphaNumeric
  4647     "
  4647     "
  4648 !
  4648 !
  4649 
  4649 
  4650 isBinarySelector
  4650 isBinarySelector
  4651     "treating the receiver as a message selector, return true if its a binary selector"
  4651     "treating the receiver as a message selector, return true if its a binary selector"
  4656 
  4656 
  4657     binopChars := Scanner binarySelectorCharacters.
  4657     binopChars := Scanner binarySelectorCharacters.
  4658     ^ (self conform:[:char | (binopChars includes:char)])
  4658     ^ (self conform:[:char | (binopChars includes:char)])
  4659 
  4659 
  4660     "
  4660     "
  4661      'foo:bar:' isBinarySelector  
  4661      'foo:bar:' isBinarySelector
  4662      #foo:bar: isBinarySelector    
  4662      #foo:bar: isBinarySelector
  4663      'hello' isBinarySelector       
  4663      'hello' isBinarySelector
  4664      '+' isBinarySelector         
  4664      '+' isBinarySelector
  4665      '|' isBinarySelector         
  4665      '|' isBinarySelector
  4666      '?' isBinarySelector         
  4666      '?' isBinarySelector
  4667      ':' isBinarySelector         
  4667      ':' isBinarySelector
  4668      'a:' isBinarySelector        
  4668      'a:' isBinarySelector
  4669      '->' isBinarySelector        
  4669      '->' isBinarySelector
  4670      '<->' isBinarySelector       
  4670      '<->' isBinarySelector
  4671      '::' isBinarySelector       
  4671      '::' isBinarySelector
  4672     "
  4672     "
  4673 
  4673 
  4674     "Modified: 4.1.1997 / 14:16:14 / cg"
  4674     "Modified: 4.1.1997 / 14:16:14 / cg"
  4675 !
  4675 !
  4676 
  4676 
  4686 isNumeric
  4686 isNumeric
  4687     "return true, if the receiver is some numeric word;
  4687     "return true, if the receiver is some numeric word;
  4688      i.e. consists only of digits."
  4688      i.e. consists only of digits."
  4689 
  4689 
  4690     self size == 0 ifTrue:[
  4690     self size == 0 ifTrue:[
  4691         ^ false
  4691 	^ false
  4692     ].
  4692     ].
  4693     self do:[:char |
  4693     self do:[:char |
  4694         char isDigit ifFalse:[^ false].
  4694 	char isDigit ifFalse:[^ false].
  4695     ].
  4695     ].
  4696     ^ true
  4696     ^ true
  4697 
  4697 
  4698     "
  4698     "
  4699      'helloWorld' isNumeric  
  4699      'helloWorld' isNumeric
  4700      'foo1234' isNumeric    
  4700      'foo1234' isNumeric
  4701      'f1234' isNumeric      
  4701      'f1234' isNumeric
  4702      '1234' isNumeric       
  4702      '1234' isNumeric
  4703      '+' isNumeric         
  4703      '+' isNumeric
  4704     "
  4704     "
  4705 !
  4705 !
  4706 
  4706 
  4707 levenshteinTo:aString
  4707 levenshteinTo:aString
  4708     "return the levenshtein distance to the argument, aString;
  4708     "return the levenshtein distance to the argument, aString;
  4722     "
  4722     "
  4723 
  4723 
  4724     ^ self levenshteinTo:aString s:4 k:2 c:1 i:2 d:6
  4724     ^ self levenshteinTo:aString s:4 k:2 c:1 i:2 d:6
  4725 
  4725 
  4726     "
  4726     "
  4727      'computer' levenshteinTo:'computer' 
  4727      'computer' levenshteinTo:'computer'
  4728      'cOmputer' levenshteinTo:'computer'  
  4728      'cOmputer' levenshteinTo:'computer'
  4729      'cOmpuTer' levenshteinTo:'computer'  
  4729      'cOmpuTer' levenshteinTo:'computer'
  4730      'cimputer' levenshteinTo:'computer'   
  4730      'cimputer' levenshteinTo:'computer'
  4731      'cumputer' levenshteinTo:'computer'   
  4731      'cumputer' levenshteinTo:'computer'
  4732 
  4732 
  4733      'cmputer' levenshteinTo:'computer'   
  4733      'cmputer' levenshteinTo:'computer'
  4734      'coomputer' levenshteinTo:'computer'  
  4734      'coomputer' levenshteinTo:'computer'
  4735 
  4735 
  4736      'ocmprt' levenshteinTo:'computer'   
  4736      'ocmprt' levenshteinTo:'computer'
  4737      'computer' levenshteinTo:'computer'
  4737      'computer' levenshteinTo:'computer'
  4738      'ocmputer' levenshteinTo:'computer'
  4738      'ocmputer' levenshteinTo:'computer'
  4739      'cmputer' levenshteinTo:'computer'
  4739      'cmputer' levenshteinTo:'computer'
  4740      'computer' levenshteinTo:'cmputer'
  4740      'computer' levenshteinTo:'cmputer'
  4741      'Computer' levenshteinTo:'computer'
  4741      'Computer' levenshteinTo:'computer'
  4742     "
  4742     "
  4743 !
  4743 !
  4744 
  4744 
  4745 levenshteinTo:aString s:substWeight k:kbdTypoWeight c:caseWeight i:insrtWeight d:deleteWeight
  4745 levenshteinTo:aString s:substWeight k:kbdTypoWeight c:caseWeight i:insrtWeight d:deleteWeight
  4746     "parametrized levenshtein. 
  4746     "parametrized levenshtein.
  4747      return the levenshtein distance to the argument, aString;
  4747      return the levenshtein distance to the argument, aString;
  4748      this value corrensponds to the number of replacements that have to be
  4748      this value corrensponds to the number of replacements that have to be
  4749      made to get aString from the receiver.
  4749      made to get aString from the receiver.
  4750      The arguments are the costs for 
  4750      The arguments are the costs for
  4751         s:substitution, 
  4751 	s:substitution,
  4752         k:keyboard type (substitution), 
  4752 	k:keyboard type (substitution),
  4753         c:case-change, 
  4753 	c:case-change,
  4754         i:insertion 
  4754 	i:insertion
  4755         d:deletion 
  4755 	d:deletion
  4756      of a character.
  4756      of a character.
  4757      See IEEE transactions on Computers 1976 Pg 172 ff"
  4757      See IEEE transactions on Computers 1976 Pg 172 ff"
  4758 
  4758 
  4759     |d  "delta matrix"
  4759     |d  "delta matrix"
  4760      len1 "{ Class: SmallInteger }"
  4760      len1 "{ Class: SmallInteger }"
  4761      len2 "{ Class: SmallInteger }"
  4761      len2 "{ Class: SmallInteger }"
  4762      dim  "{ Class: SmallInteger }"
  4762      dim  "{ Class: SmallInteger }"
  4763      prevRow row col 
  4763      prevRow row col
  4764      dimPlus1 "{ Class: SmallInteger }"
  4764      dimPlus1 "{ Class: SmallInteger }"
  4765      min pp c1 c2|
  4765      min pp c1 c2|
  4766 
  4766 
  4767     len1 := self size.
  4767     len1 := self size.
  4768     len2 := aString size.
  4768     len2 := aString size.
  4772     dim := len1 max:len2.
  4772     dim := len1 max:len2.
  4773     dimPlus1 := dim + 1.
  4773     dimPlus1 := dim + 1.
  4774 
  4774 
  4775     d := Array new:dimPlus1.
  4775     d := Array new:dimPlus1.
  4776     1 to:dimPlus1 do:[:i |
  4776     1 to:dimPlus1 do:[:i |
  4777         d at:i put:(Array new:dimPlus1)
  4777 	d at:i put:(Array new:dimPlus1)
  4778     ].
  4778     ].
  4779 
  4779 
  4780     "init help-matrix"
  4780     "init help-matrix"
  4781 
  4781 
  4782     (d at:1) at:1 put:0.
  4782     (d at:1) at:1 put:0.
  4783     row := d at:1.
  4783     row := d at:1.
  4784     1 to:dim do:[:j |
  4784     1 to:dim do:[:j |
  4785         row at:(j + 1) put:( (row at:j) + insrtWeight )
  4785 	row at:(j + 1) put:( (row at:j) + insrtWeight )
  4786     ].
  4786     ].
  4787 
  4787 
  4788     1 to:dim do:[:i |
  4788     1 to:dim do:[:i |
  4789          (d at:(i + 1)) at:1 put:(  ((d at:i) at:1) + deleteWeight )
  4789 	 (d at:(i + 1)) at:1 put:(  ((d at:i) at:1) + deleteWeight )
  4790     ].
  4790     ].
  4791 
  4791 
  4792     1 to:len1 do:[:i |
  4792     1 to:len1 do:[:i |
  4793         c1 := self at:i.
  4793 	c1 := self at:i.
  4794         1 to:len2 do:[:j |
  4794 	1 to:len2 do:[:j |
  4795             c2 := aString at:j.
  4795 	    c2 := aString at:j.
  4796             (c1 == c2) ifTrue:[
  4796 	    (c1 == c2) ifTrue:[
  4797                 pp := 0
  4797 		pp := 0
  4798             ] ifFalse:[
  4798 	    ] ifFalse:[
  4799                 (c1 asLowercase == c2 asLowercase) ifTrue:[
  4799 		(c1 asLowercase == c2 asLowercase) ifTrue:[
  4800                     pp := caseWeight
  4800 		    pp := caseWeight
  4801                 ] ifFalse:[
  4801 		] ifFalse:[
  4802                     pp := substWeight.
  4802 		    pp := substWeight.
  4803                     substWeight ~~ kbdTypoWeight ifTrue:[
  4803 		    substWeight ~~ kbdTypoWeight ifTrue:[
  4804                         (DoWhatIMeanSupport isKey:c1 asLowercase nextTo:c2 asLowercase) ifTrue:[
  4804 			(DoWhatIMeanSupport isKey:c1 asLowercase nextTo:c2 asLowercase) ifTrue:[
  4805                             pp := kbdTypoWeight.
  4805 			    pp := kbdTypoWeight.
  4806                         ].
  4806 			].
  4807                     ].
  4807 		    ].
  4808                 ]
  4808 		]
  4809             ].
  4809 	    ].
  4810             prevRow := d at:i.
  4810 	    prevRow := d at:i.
  4811             row := d at:(i + 1).
  4811 	    row := d at:(i + 1).
  4812             col := j + 1.
  4812 	    col := j + 1.
  4813             min := (prevRow at:j) + pp.
  4813 	    min := (prevRow at:j) + pp.
  4814             min := min min:( (row at:j) + insrtWeight).
  4814 	    min := min min:( (row at:j) + insrtWeight).
  4815             min := min min:( (prevRow at:col) + deleteWeight).
  4815 	    min := min min:( (prevRow at:col) + deleteWeight).
  4816             row at:col put: min
  4816 	    row at:col put: min
  4817         ]
  4817 	]
  4818     ].
  4818     ].
  4819 
  4819 
  4820     ^ (d at:(len1 + 1)) at:(len2 + 1)
  4820     ^ (d at:(len1 + 1)) at:(len2 + 1)
  4821 !
  4821 !
  4822 
  4822 
  4824     "treating the receiver as a message selector, return how many arguments would it take"
  4824     "treating the receiver as a message selector, return how many arguments would it take"
  4825 
  4825 
  4826     |binopChars firstChar|
  4826     |binopChars firstChar|
  4827 
  4827 
  4828     (self size > 2) ifFalse:[
  4828     (self size > 2) ifFalse:[
  4829         binopChars := Scanner binarySelectorCharacters.
  4829 	binopChars := Scanner binarySelectorCharacters.
  4830         firstChar := self at:1.
  4830 	firstChar := self at:1.
  4831 
  4831 
  4832         (self size == 1) ifTrue:[
  4832 	(self size == 1) ifTrue:[
  4833             (binopChars includes:firstChar) ifFalse:[^ 0].
  4833 	    (binopChars includes:firstChar) ifFalse:[^ 0].
  4834             ^ 1
  4834 	    ^ 1
  4835         ].
  4835 	].
  4836         (binopChars includes:firstChar) ifTrue:[
  4836 	(binopChars includes:firstChar) ifTrue:[
  4837             (binopChars includes:(self at:2)) ifTrue:[^ 1]
  4837 	    (binopChars includes:(self at:2)) ifTrue:[^ 1]
  4838         ]
  4838 	]
  4839     ].
  4839     ].
  4840     ^ self occurrencesOf:$:
  4840     ^ self occurrencesOf:$:
  4841 
  4841 
  4842     "
  4842     "
  4843      'foo:bar:' numArgs  
  4843      'foo:bar:' numArgs
  4844      #foo:bar: numArgs    
  4844      #foo:bar: numArgs
  4845      'hello' numArgs       
  4845      'hello' numArgs
  4846      '+' numArgs   
  4846      '+' numArgs
  4847      '|' numArgs   
  4847      '|' numArgs
  4848      '?' numArgs   
  4848      '?' numArgs
  4849     "
  4849     "
  4850 
  4850 
  4851     "Modified: 4.1.1997 / 14:16:14 / cg"
  4851     "Modified: 4.1.1997 / 14:16:14 / cg"
  4852 !
  4852 !
  4853 
  4853 
  4869 	coll add:(self copyFrom:idx1 to:idx2).
  4869 	coll add:(self copyFrom:idx1 to:idx2).
  4870 	idx1 := idx2 + 1
  4870 	idx1 := idx2 + 1
  4871     ].
  4871     ].
  4872 
  4872 
  4873     "
  4873     "
  4874      'foo:bar:' partsIfSelector     
  4874      'foo:bar:' partsIfSelector
  4875      #foo:bar: partsIfSelector     
  4875      #foo:bar: partsIfSelector
  4876      'hello' partsIfSelector       
  4876      'hello' partsIfSelector
  4877      '+' partsIfSelector           
  4877      '+' partsIfSelector
  4878     "
  4878     "
  4879 !
  4879 !
  4880 
  4880 
  4881 spellAgainst: aString 
  4881 spellAgainst: aString
  4882     "return an integer between 0 and 100 indicating how similar 
  4882     "return an integer between 0 and 100 indicating how similar
  4883      the argument is to the receiver.  No case conversion is done.
  4883      the argument is to the receiver.  No case conversion is done.
  4884      This algorithm is much simpler (but also less exact) than the
  4884      This algorithm is much simpler (but also less exact) than the
  4885      levenshtein distance. Experiment which is better for your
  4885      levenshtein distance. Experiment which is better for your
  4886      application."
  4886      application."
  4887 
  4887 
  4901     i1 := i2 := 1.
  4901     i1 := i2 := 1.
  4902     [i1 <= size1 and: [i2 <= size2]] whileTrue:[
  4902     [i1 <= size1 and: [i2 <= size2]] whileTrue:[
  4903 	next1 := i1 + 1.
  4903 	next1 := i1 + 1.
  4904 	next2 := i2 + 1.
  4904 	next2 := i2 + 1.
  4905 	(self at:i1) == (aString at:i2) ifTrue: [
  4905 	(self at:i1) == (aString at:i2) ifTrue: [
  4906 	    score := score+1.             
  4906 	    score := score+1.
  4907 	    i1 := next1.                    
  4907 	    i1 := next1.
  4908 	    i2 := next2
  4908 	    i2 := next2
  4909 	] ifFalse: [
  4909 	] ifFalse: [
  4910 	    (i2 < size2 and: [(self at:i1) == (aString at:next2)]) ifTrue: [
  4910 	    (i2 < size2 and: [(self at:i1) == (aString at:next2)]) ifTrue: [
  4911 		i2 := next2
  4911 		i2 := next2
  4912 	    ] ifFalse: [
  4912 	    ] ifFalse: [
  4913 		(i1 < size1 and: [(self at:next1) == (aString at:i2)]) ifTrue: [
  4913 		(i1 < size1 and: [(self at:next1) == (aString at:i2)]) ifTrue: [
  4914 		    i1 := next1
  4914 		    i1 := next1
  4915 		] ifFalse: [
  4915 		] ifFalse: [
  4916 		    i1 := next1.
  4916 		    i1 := next1.
  4917 		    i2 := next2
  4917 		    i2 := next2
  4918 		] 
  4918 		]
  4919 	    ] 
  4919 	    ]
  4920 	] 
  4920 	]
  4921     ].
  4921     ].
  4922 
  4922 
  4923     score == maxLen ifTrue: [^ 100].
  4923     score == maxLen ifTrue: [^ 100].
  4924     ^ 100 * score // maxLen
  4924     ^ 100 * score // maxLen
  4925 
  4925 
  4926     " 
  4926     "
  4927      'Smalltalk' spellAgainst: 'Smalltlak' 
  4927      'Smalltalk' spellAgainst: 'Smalltlak'
  4928      'Smalltalk' spellAgainst: 'smalltlak' 
  4928      'Smalltalk' spellAgainst: 'smalltlak'
  4929      'Smalltalk' spellAgainst: 'smalltalk' 
  4929      'Smalltalk' spellAgainst: 'smalltalk'
  4930      'Smalltalk' spellAgainst: 'smalltlk'  
  4930      'Smalltalk' spellAgainst: 'smalltlk'
  4931      'Smalltalk' spellAgainst: 'Smalltolk'   
  4931      'Smalltalk' spellAgainst: 'Smalltolk'
  4932     "
  4932     "
  4933 !
  4933 !
  4934 
  4934 
  4935 startsWith:aString
  4935 startsWith:aString
  4936     "return true, if the receiver starts with something, aString.
  4936     "return true, if the receiver starts with something, aString.
  4937      If the argument is empty, true is returned."
  4937      If the argument is empty, true is returned."
  4938 
  4938 
  4939     |s|
  4939     |s|
  4940 
  4940 
  4941     (s := self string) ~~ self ifTrue:[
  4941     (s := self string) ~~ self ifTrue:[
  4942         ^ s startsWith:aString
  4942 	^ s startsWith:aString
  4943     ].
  4943     ].
  4944     ^ super startsWith:aString
  4944     ^ super startsWith:aString
  4945 
  4945 
  4946     "
  4946     "
  4947      'hello world' startsWith:'hello'                 
  4947      'hello world' startsWith:'hello'
  4948      'hello world' asText allBold startsWith:'hello'  
  4948      'hello world' asText allBold startsWith:'hello'
  4949      'hello world' asText allBold startsWith:''  
  4949      'hello world' asText allBold startsWith:''
  4950     "
  4950     "
  4951 
  4951 
  4952     "Created: 12.5.1996 / 15:46:40 / cg"
  4952     "Created: 12.5.1996 / 15:46:40 / cg"
  4953     "Modified: 12.5.1996 / 15:49:24 / cg"
  4953     "Modified: 12.5.1996 / 15:49:24 / cg"
  4954 ! !
  4954 ! !
  4971 ! !
  4971 ! !
  4972 
  4972 
  4973 !CharacterArray class methodsFor:'documentation'!
  4973 !CharacterArray class methodsFor:'documentation'!
  4974 
  4974 
  4975 version
  4975 version
  4976     ^ '$Header: /cvs/stx/stx/libbasic/CharacterArray.st,v 1.314 2005-04-20 14:59:45 cg Exp $'
  4976     ^ '$Header: /cvs/stx/stx/libbasic/CharacterArray.st,v 1.315 2005-04-28 17:29:30 cg Exp $'
  4977 ! !
  4977 ! !
  4978 
  4978 
  4979 CharacterArray initialize!
  4979 CharacterArray initialize!