I find that there is no built-in trim (strip)
method to remove leading and trailing spaces from strings in the built-in String
class. I want to extend it with my functions. Is it possible? Using example here, I tried following code:
String extend [
trimleading: str [ |ch ret flag|
ret := str. "make a copy of sent string"
flag := true.
[flag] whileTrue: [ "while first char is space"
ch := ret first: 1. "again test first char"
ch = ' ' "check if space remaining"
ifTrue: [ ret := (ret copyFrom: 2 to: ret size)] "copy from 2nd char"
ifFalse: [flag := false]
].
^ret "return modified string"
]
trim: str [ |ret|
ret := str.
ret := (self trimleading: ret). "trim leading spaces"
ret := (self trimleading: (ret reverse)). "reverse string and repeat trim leading"
^(ret reverse) "return re-reversed string"
]
].
oristr := ' this is a test '
('>>',oristr,'<<') displayNl.
('>>',(oristr trim),'<<') displayNl.
Above code does not work and gives following error:
$ gst string_extend_trim.st
>> this is a test <<
Object: ' this is a test ' error: did not understand #trim
MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
String(Object)>>doesNotUnderstand: #trim (SysExcept.st:1448)
UndefinedObject>>executeStatements (string_extend_trim.st:23)
Where is the problem and how can it be corrected? Thanks.
Edit: Following code works but it does not change original string:
String extend [
trimleading [ |ch ret flag|
ret := self. "make a copy of sent string"
flag := true.
[flag] whileTrue: [ "while first char is space"
ch := ret first: 1. "again test first char"
ch = ' ' "check if space remaining"
ifTrue: [ ret := (ret copyFrom: 2 to: ret size)] "copy from 2nd char"
ifFalse: [flag := false]
].
^ret "return modified string"
]
trim [ |ret|
ret := self.
ret := (self trimleading). "trim leading spaces"
ret := ((ret reverse) trimleading ). "reverse string and repeat trim leading"
^(ret reverse) "return re-reverse string"
]
].
oristr := ' this is a test '
('>>',oristr,'<<') displayNl.
('>>',(oristr trim),'<<') displayNl.
('>>',oristr,'<<') displayNl.
oristr := (oristr trim).
('>>',oristr,'<<') displayNl.
How can oristr trim
change oristr
? I do not want to write oristr := oristr trim
.
The first problem you already solved: originally you defined a method trim:
with one argument but sent trim
with no arguments.
The second problem is to modify the String in place. You can change the chars with self at: index put: aCharacter
and some other methods to copy and overwrite ranges, but you won't be able to change the size (length) of the String. In the Smalltalks I know, Objects cannot change their size after they have been created. Therefore I propose that you stick to making a new String with less characters in trim
.
There is a method to exchange one object for another everywhere in the System. It is called become:
. But I think you should not use it here. Depending on the Smalltalk implementation you might end up with unwanted side effects, such as replacing a String literal in a method (so the next method invocation would actually run with a different, trimmed string in place of the literal).