Hello List,
I've been struggling a bit with some basics about Strings for which I couldn't find an answer (yet). 1) How to construct a String from Characters? For example, I want to construct a String from the Chatacter literals: $H $I Character cr $T $H $E $R $E 2) How to replace a sequence of Characters in a String for others? For exaple, I want to replace every 'HI' (in this case only one) for 'HELLO' in the String above (not necesarily destructively, getting a new String is also ok). Is there a quick way to do that? Thanks in advance! Sebastian _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
Sebastian Nozzi wrote:
> Hello List, > > I've been struggling a bit with some basics about Strings for which I > couldn't find an answer (yet). > > 1) How to construct a String from Characters? > > For example, I want to construct a String from the Chatacter literals: > > $H $I > Character cr > $T $H $E $R $E Dirty solution: |col str | col := OrderedCollection new. col add:$H ;add: $I; add: (Character cr); add:$T; add: $H; add: $E; add: $R; add: $E. str := String new. col do: [:element | str := str, element asString]. ^str. This probably creates a bunch of unnecessary string objects, but I can never remember the best implementation. > 2) How to replace a sequence of Characters in a String for others? > > For exaple, I want to replace every 'HI' (in this case only one) for > 'HELLO' in the String above (not necesarily destructively, getting a > new String is also ok). Is there a quick way to do that? How about this? | str3 str2 str index | str := 'HI THERE'. str2 := 'HI'. index := str findString: 'HI'. "str := str replaceFrom: index to: str2 size with: 'HELLO' startingAt:1." str3 := 'HELLO', (str copyFrom: (index + str2 size) to: (str size)). ^str3 _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
In reply to this post by Sebastian Nozzi-2
On Mon, Feb 2, 2009 at 8:46 AM, Sebastian Nozzi <[hidden email]> wrote: Now, I know that there are also more advanced things you can do, such as replacing using regular expressions, but I think that is in a downloadable package somewhere. You'll need to Google for it.Hello List, If you're dealing with less than four characters, you could do: a := String with: $H with: $I with: Character cr with: $T. Otherwise, I'm not aware of any trivial way to do this. The first issue is that you need to have all those characters available as a collection somehow (without using a String). My best effort, without adding convenience methods to the String class, is: a := #( $H $I $- $T $H $E $R $E ). "Makes an array of literals - I never liked this syntax though" You have to manually put the "Character cr" in there; I'm not aware of any way to declare it as a literal like that: a at: 3 put: Character cr. And then you can do Smalltalk magic with it: b := a inject: '' into: [ :each :sum | each, sum asString]. "Makes 8 copies of a String; inefficient" If there were more than just a handful of characters (e.g. writing to a file), then you'd want to use streams instead: c := WriteStream on: (String new: a size). " It's important to make a good estimate of size here " c nextPutAll: a. b := c contents. c is a stream with a String as a target, so "nextPutAll:" will accept any collection of characters and "nextPut:" will accept any individual character.
This is something that I don't know off the top of my head, so I'm going to give you a small insight as to how I work this out. First, I bring up the browser and intuitively go to the String class. I have a quick look at the method categories, and see "converting" and "copying" which might be useful. I notice "copyReplaceTokens:with:" which invokes "copyReplaceAll:with:asTokens". I highlight the invocation of "copyReplaceAll:with:asTokens" and press alt-m to see which classes implement this. But then a little lightbulb goes off in my head; perhaps "copyReplaceAll:with:" exists. It does - in class SequencableCollection. I also discover "replaceAll:with" on a hunch as well, but it doesn't work and doesn't give any errors. A bug maybe? So you can do this: d := b copyReplaceAll: 'HI' with: 'HELLO'. Gulik. -- http://people.squeakfoundation.org/person/mikevdg http://gulik.pbwiki.com/ _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
In reply to this post by Sebastian Nozzi-2
Great question.
To deal with the input characters, it is useful to have them in an array. A traditional Smalltalk array with characters would look like this #($a $b $c) but it isn't obvious what to do with the carriage return. For this, the Squeak brace array is handy and also works in Pharo. characters := {$H.$I.Character cr. $T.$H.$E.$R.$E}. It isn't terribly portable to other Smalltalks, but it sure is easy to type. Now we've got an array of characters, how to create the new String? Another Squeak-ism is the class method #streamContents:. It takes a one argument block. The argument is a writeable stream that will return its contents at the end. I have to admit I was thrown by it the first time I saw it. string := String streamContents: [:writeStream | characters do: [:c | writeStream nextPut: c]]. Like the brace array, it isn't very portable to other Smalltalks, but it is pretty handy. That leaves us with replacing. I opened the method finder and typed replace into the search box. That gives us the following complete solution: | characters string | characters := {$H.$I.Character cr. $T.$H.$E.$R.$E}. string := String streamContents: [:writeStream | characters do: [:c | writeStream nextPut: c]]. string copyReplaceAll: 'HI' with: 'HELLO' I also posted this to my blog (with a picture of the Method Finder) http://www.withaguide.com/2009/02/characters-strings-and-things.html On Sun, Feb 1, 2009 at 1:46 PM, Sebastian Nozzi <[hidden email]> wrote: > > Hello List, > > I've been struggling a bit with some basics about Strings for which I > couldn't find an answer (yet). > > 1) How to construct a String from Characters? > > For example, I want to construct a String from the Chatacter literals: > > $H $I > Character cr > $T $H $E $R $E > > 2) How to replace a sequence of Characters in a String for others? > > For exaple, I want to replace every 'HI' (in this case only one) for > 'HELLO' in the String above (not necesarily destructively, getting a > new String is also ok). Is there a quick way to do that? > > Thanks in advance! > > Sebastian > _______________________________________________ > Beginners mailing list > [hidden email] > http://lists.squeakfoundation.org/mailman/listinfo/beginners Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
>>>>> "David" == David Mitchell <[hidden email]> writes:
David> | characters string | David> characters := {$H.$I.Character cr. $T.$H.$E.$R.$E}. David> string := String streamContents: [:writeStream | characters do: [:c | David> writeStream nextPut: c]]. chars := {$H.$I.Character cr. $T.$H.$E.$R.$E}. string := chars as: String. Far simpler. Look at #as:... it's a pretty good "force this into that" call. -- Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <[hidden email]> <URL:http://www.stonehenge.com/merlyn/> Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc. See http://methodsandmessages.vox.com/ for Smalltalk and Seaside discussion _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
To all whom I wrote that I found it strange that there was no class
method to construct a String from an array... I was wrong! I debugged Randal's suggestion of using "as: String" and the result that "newFrom: aCollection" is called. So, the solution could also be: string := String newFrom: {$H.$I.Character cr. $T.$H.$E.$R.$E}. Of course, to make it completely portable you could also use two ways that have been suggested: add every character into an OrderedCollection and use that, or use a standard array-literal and manually #put: the carriage-return afterwards. Thank you again for your answers, Sebastian > 2009/2/1 Randal L. Schwartz <[hidden email]>: >>>>>>> "David" == David Mitchell <[hidden email]> writes: >> >> David> | characters string | >> David> characters := {$H.$I.Character cr. $T.$H.$E.$R.$E}. >> David> string := String streamContents: [:writeStream | characters do: [:c | >> David> writeStream nextPut: c]]. >> >> chars := {$H.$I.Character cr. $T.$H.$E.$R.$E}. >> string := chars as: String. >> >> Far simpler. Look at #as:... it's a pretty good "force this into that" >> call. >> >> -- >> Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 >> <[hidden email]> <URL:http://www.stonehenge.com/merlyn/> >> Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc. >> See http://methodsandmessages.vox.com/ for Smalltalk and Seaside discussion Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
In reply to this post by Sebastian Nozzi-2
Is there something wrong with just doing:
string := 'Hello There'. ? Ken G. Brown >Date: Mon, 2 Feb 2009 11:57:51 +0100 >From: Sebastian Nozzi <[hidden email]> >Subject: Re: [Newbies] String construction and replacement >To: [hidden email] >Message-ID: > <[hidden email]> >Content-Type: text/plain; charset=UTF-8 > >To all whom I wrote that I found it strange that there was no class >method to construct a String from an array... I was wrong! > >I debugged Randal's suggestion of using "as: String" and the result >that "newFrom: aCollection" is called. So, the solution could also be: > >string := String newFrom: {$H.$I.Character cr. $T.$H.$E.$R.$E}. > >Of course, to make it completely portable you could also use two ways >that have been suggested: add every character into an >OrderedCollection and use that, or use a standard array-literal and >manually #put: the carriage-return afterwards. > >Thank you again for your answers, > >Sebastian > > >> 2009/2/1 Randal L. Schwartz <[hidden email]>: >>>>>>>> "David" == David Mitchell <[hidden email]> writes: >>> >>> David> | characters string | >>> David> characters := {$H.$I.Character cr. $T.$H.$E.$R.$E}. >>> David> string := String streamContents: [:writeStream | characters do: [:c | >>> David> writeStream nextPut: c]]. >>> >>> chars := {$H.$I.Character cr. $T.$H.$E.$R.$E}. >>> string := chars as: String. >>> >>> Far simpler. Look at #as:... it's a pretty good "force this into that" >>> call. >>> >>> -- >>> Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 >>> <[hidden email]> <URL:http://www.stonehenge.com/merlyn/> >>> Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc. > >> See http://methodsandmessages.vox.com/ for Smalltalk and Seaside discussion Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
In reply to this post by Sebastian Nozzi-2
No, actually no.
But the background to my question (which I didn't mention since it doesn't belong to this list) is that I was dealing with a Seaside issue in which one string's newlines came back with CR+LF (carriage return and line feed) and under other conditions it came back as having LF+LF. I wanted to construct a String for these exact sequences and do the appropriate replacement (that is replace all LF+LF ocurrences for CR+LF). I am very glad that in Smalltalk it's possible to write a string-literal like you did (with a newline in-between). 2009/2/2 Ken G. Brown <[hidden email]>: > Is there something wrong with just doing: > > string := 'Hello > There'. > > ? > > Ken G. Brown _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
For your particular need (normalizing line breaks), use:
aString withSqueakLineEndings That gives you a defined line end convention, suitable for use with other methods like linesDo:. HTH Matthias On Mon, Feb 2, 2009 at 4:09 PM, Sebastian Nozzi <[hidden email]> wrote: > No, actually no. > > But the background to my question (which I didn't mention since it > doesn't belong to this list) is that I was dealing with a Seaside > issue in which one string's newlines came back with CR+LF (carriage > return and line feed) and under other conditions it came back as > having LF+LF. > > I wanted to construct a String for these exact sequences and do the > appropriate replacement (that is replace all LF+LF ocurrences for > CR+LF). > > > I am very glad that in Smalltalk it's possible to write a > string-literal like you did (with a newline in-between). > > 2009/2/2 Ken G. Brown <[hidden email]>: >> Is there something wrong with just doing: >> >> string := 'Hello >> There'. >> >> ? >> >> Ken G. Brown > _______________________________________________ > Beginners mailing list > [hidden email] > http://lists.squeakfoundation.org/mailman/listinfo/beginners > Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
In reply to this post by Claus Kick
Claus Kick wrote:
>> 2) How to replace a sequence of Characters in a String for others? >> >> For exaple, I want to replace every 'HI' (in this case only one) for >> 'HELLO' in the String above (not necesarily destructively, getting a >> new String is also ok). Is there a quick way to do that? > > > How about this? > > | str3 str2 str index | > > str := 'HI THERE'. > str2 := 'HI'. > > index := str findString: 'HI'. > "str := str replaceFrom: index to: str2 size with: 'HELLO' startingAt:1." > > str3 := 'HELLO', (str copyFrom: (index + str2 size) to: (str size)). > ^str3 Woops, thats hardly generic ... str := 'HI THERE BLA HI HERE'. answer := (str (asArrayOfSubstringsSeparatedBy: (Character space))) asOrderedCollection. pattern := 'HI'. replacement := 'HELLO'. resultString := ''. i := 1. answer do:[:element | (element = pattern ) ifTrue:[i = 1 ifTrue:[resultString := resultString, replacement . i := i + i] ifFalse:[resultString := resultString, ' ', replacement ]] ifFalse:[resultString := resultString, ' ', element]]. ^resultString. _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
>>>>> "Claus" == Claus Kick <[hidden email]> writes:
Claus> pattern := 'HI'. Claus> replacement := 'HELLO'. Claus> resultString := ''. Claus> i := 1. Claus> answer do:[:element | (element = pattern ) ifTrue:[i = 1 ifTrue:[resultString Claus> := resultString, replacement . i := i + i] ifFalse:[resultString := Claus> resultString, ' ', replacement ]] ifFalse:[resultString := resultString, ' ', Claus> element]]. Claus> ^resultString. That sort of "build a string by repeated concatenation" scares me. Might be ok for very short things, but for longer things, learn to use streams. For example, look at the implementation of String>>expandMacrosWithArguments: to see how to use a ReadStream on the source and WriteStream to hold the destination. Also, if the logic gets to be nested blocks, I try to refactor that rather quickly. -- Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <[hidden email]> <URL:http://www.stonehenge.com/merlyn/> Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc. See http://methodsandmessages.vox.com/ for Smalltalk and Seaside discussion _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
Randal L. Schwartz wrote:
>>>>>>"Claus" == Claus Kick <[hidden email]> writes: > > > Claus> pattern := 'HI'. > Claus> replacement := 'HELLO'. > Claus> resultString := ''. > Claus> i := 1. > Claus> answer do:[:element | (element = pattern ) ifTrue:[i = 1 ifTrue:[resultString > Claus> := resultString, replacement . i := i + i] ifFalse:[resultString := > Claus> resultString, ' ', replacement ]] ifFalse:[resultString := resultString, ' ', > Claus> element]]. > Claus> ^resultString. > > That sort of "build a string by repeated concatenation" scares me. Might > be ok for very short things, but for longer things, learn to use streams. Honestly, I never think of Streams in this context. One day, I might actually remember to use them. > For example, look at the implementation of String>>expandMacrosWithArguments: > to see how to use a ReadStream on the source and WriteStream to hold the > destination. Ah, ok, I will really note this down this time. > Also, if the logic gets to be nested blocks, I try to refactor that > rather quickly. How would you refactor something like that? _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
>>>>> "Claus" == Claus Kick <[hidden email]> writes:
Claus> How would you refactor something like that? If you can, get a copy of Kent Beck's "Smalltalk Best Practice Patterns". But the key thing to keep in mind is that anything that isn't just a simple message send (unary, binary or keyword) has some subsequence of one or more message sends that can be pulled out and named separately with an intention-revealing selector, providing both code reuse, and clarity. -- Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <[hidden email]> <URL:http://www.stonehenge.com/merlyn/> Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc. See http://methodsandmessages.vox.com/ for Smalltalk and Seaside discussion _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
Free forum by Nabble | Edit this page |