prototypes addSlot: #Character valued: ASCIICharacter. ASCIICharacter traits addSlot: #Whitespace valued: '\s\t\n\v\f\r'. ASCIICharacter traits addSlot: #Vowels valued: 'AEIOUaeiou'. [| ct ac | ct: prototypes Character traits. ct addSlot: #allChars. ct allChars: (Array newSize: 256). ac: ct allChars. 0 below: 256 do: [| :each | ac at: each put: (each as: Character)]. ac ]. a@(ASCIICharacter traits) cr [$\n]. a@(ASCIICharacter traits) tab [$\t]. a@(ASCIICharacter traits) space [$\s]. a@(ASCIICharacter traits) = b@(ASCIICharacter traits) [ (a as: Integer) = (b as: Integer) ]. ch@(ASCIICharacter traits) hash [ ch as: Integer ]. ch@(ASCIICharacter traits) isAlphanumeric [ ch isLetter or: [ch isDigit] ]. ch@(ASCIICharacter traits) isWhitespace [ ch Whitespace includes: ch ]. ch@(ASCIICharacter traits) isDigit: radix [| value | value: (ch as: Integer). (value >= 48 and: [value <= 57]) ifTrue: [^ (value - 48 < radix)]. (value >= 65 and: [value <= 90]) ifTrue: [^ (value - 65 < (radix - 10))]. (value >= 97 and: [value <= 122]) ifTrue: [^ (value - 97 < (radix - 10))]. False ]. ch@(ASCIICharacter traits) isDigit [ ch isDigit: 10 ]. ch@(ASCIICharacter traits) toDigit: radix [| value | (ch isDigit: radix) ifFalse: [^ Nil]. value: (ch as: Integer). value >= 97 ifTrue: [^ (value - 97 + 10)]. value >= 65 ifTrue: [^ (value - 65 + 10)]. value >= 48 ifTrue: [^ (value - 48)]. Nil ]. ch@(ASCIICharacter traits) toDigit [ ch toDigit: 10 ]. ch@(ASCIICharacter traits) isLetter [ ch isUppercase or: [ch isLowercase] ]. ch@(ASCIICharacter traits) isLowercase [| value | value: (ch as: Integer). 97 <= value and: [value <= 122] ]. ch@(ASCIICharacter traits) toUppercase [ ch isLowercase ifTrue: [(ch as: Integer) - 32 as: ASCIICharacter] ifFalse: [ch] ]. ch@(ASCIICharacter traits) isUppercase [| value | value: (ch as: Integer). 65 <= value and: [value <= 90] ]. ch@(ASCIICharacter traits) toLowercase [ ch isUppercase ifTrue: [(ch as: Integer) + 32 as: ch] ifFalse: [ch] ]. ch@(ASCIICharacter traits) isVowel [ ch Vowels includes: ch ]. prototypes String traits addDelegate: #parent2 valued: Sequence traits. "Ensures that String captures Sequence behavior and features." _@(String traits) accepts: _@(Root traits) [False]. _@(String traits) accepts: _@(Character traits) [True]. s@(String traits) toUppercase [ s doWithIndex: [| :each :index | s at: index put: each toUppercase] ]. s@(String traits) toLowercase [ s doWithIndex: [| :each :index | s at: index put: each toLowercase] ]. s@(String traits) toSwapCase [ s doWithIndex: [| :each :index | each isLowercase ifTrue: [s at: index put: each toUppercase] ifFalse: [s at: index put: each toLowercase]] ]. s@(String traits) printOn: stream [ stream nextPut: $'. stream nextPutAll: s. stream nextPut: $'. ]. ch@(ASCIICharacter traits) rot13 [| value upper | upper: ch isUppercase. value: (ch toLowercase as: Integer). (value >= ($a as: Integer)) /\ (value < ($n as: Integer)) ifTrue: [value: value + 13] ifFalse: [(value > ($m as: Integer)) /\ (value <= ($z as: Integer)) ifTrue: [value: value - 13]]. upper ifTrue: [(value as: Character) toUppercase] ifFalse: [value as: Character] ]. s@(String traits) rot13 [| value | s doWithIndex: [| :each :index | s at: index put: each rot13] ]. s@(String traits) indexPast: delims startingAt: start "Answer the index of the character within the receiver, starting at start, that does NOT match one of the delimiters. If the receiver does not contain any of the delimiters, answer size. Assumes the delimiters to be a non-empty string." [ start below: s size do: [| :index | delims detect: [| :c | c = (s at: index)] ifNone: [^ index]]. s size ]. s@(String traits) firstIndexOf: delims startingAt: start "Answer the first occurrence of a character in the delimiters, starting at start, returning size on failure." [ start below: s size do: [| :index | delims do: [| :c | c = (s at: index) ifTrue: [^ index]]]. s size ]. s@(String traits) splitWith: c@(Character traits) [ s splitWith: {c} ]. s@(String traits) splitWith: delims@(String traits) "Answer the Sequence of substrings resulting from splitting the string with the given delimiting characters." [| subStrings keyStart keyEnd | subStrings: ExtensibleSequence newEmpty. keyEnd: 0. [keyEnd < s size] whileTrue: [keyStart: (s indexPast: delims startingAt: keyEnd). keyEnd: (s firstIndexOf: delims startingAt: keyStart). keyStart < keyEnd ifTrue: [subStrings add: (s copyFrom: keyStart to: keyEnd - 1)]]. subStrings ].