String lines doesn't handle separating Excel copy-and-paste very well, because soft enters in a cell get splitted into separate lines.
Ive done now:
splitIntoLines: aString "Return a collection with the string-lines of the receiver."
| input char temp inQuote| input := aString readStream. ^ Array streamContents: [ :output | temp := ''. inQuote := false. [ input atEnd ] whileFalse: [ char := input next. char = $" ifTrue: [ inQuote ifTrue:[ input peek = (Character tab) ifTrue: [ char := input next.]. input peek = (Character cr) ifTrue: [ char := input next. inQuote := false]]]. char = (Character tab) ifTrue:[ inQuote ifTrue: [ inQuote := false] ifFalse: [ input peek= $" ifTrue: [ input next. inQuote:=true]]]. char = (Character cr) ifFalse: [temp := temp, char asString] ifTrue: [ inQuote ifFalse: [ output nextPut: temp. temp:=''. input peek = Character lf ifTrue: [input next]]]]]
I would be interested in (speed & elegance & mistakes) improvements to it.
Stephan
Hi Stephan,
It's a bit hard to understand. Especially without tests. I would probably split it into a few methods such that each method tells the reader a manageable chunk of what is going on. I've sketched a few other things as well to give you some ideas:
splitIntoLines: aString | in | in := aString readStream. ^ Array streamContents: [:out | [in atEnd] whileFalse: [ out nextPut: (self readLine: in) ] ]
readLine: aStream inQuote := false. "instance variable " " Use a stream to build the string instead of #, " ^ String streamContents: [:out | | char | " Give clear indication of what an end of line is " [((char := aStream next) = Character cr) and: [inQuote not]] whileFalse: [self readNext: aStream onto: out]. " Use stream methods where you can" aStream peekFor: Character lf]
readNext: inStream onto: outStream | char | char := inStream last. " the loop calls next for us " " This used to be ifTrue: [ ifTrue: [ with no ifFalse: " (char = $" and: [inQuote]) ifTrue:[ " Common tasks given to helper methods " char := self lookFor: Character tab on: inStream. char := self lookFor: Character tab on: inStream ifFound: [inQuote := false]. ]. char = (Character tab) ifTrue:[ inQuote ifTrue: [inQuote := false] ifFalse: [ self lookFor: Character tab in: aStream ifFound: [inQuote := false]. ] ]. " BTW, not sure this was right - don't you want CRs that aren't part of EOLs? " char = (Character cr) ifFalse: [out nextPut: char]
lookFor: aCharacter in: aStream ^ self lookFor: aCharacter in: aStream ifFound: []
lookFor: aCharacter in: aStream ifFound: aBlock aStream peek = aCharacter ifTrue: [ aBlock value. ^ aStream next. ]. ^ aStream last
Hope this helps,
Zulq.
stephan@stack.nl wrote:
String lines doesn't handle separating Excel copy-and-paste very well, because soft enters in a cell get splitted into separate lines.
Ive done now:
splitIntoLines: aString "Return a collection with the string-lines of the receiver."
| input char temp inQuote| input := aString readStream. ^ Array streamContents: [ :output | temp := ''. inQuote := false. [ input atEnd ] whileFalse: [ char := input next. char = $" ifTrue: [ inQuote ifTrue:[ input peek = (Character tab) ifTrue: [ char := input next.]. input peek = (Character cr) ifTrue: [ char := input next. inQuote := false]]]. char = (Character tab) ifTrue:[ inQuote ifTrue: [ inQuote := false] ifFalse: [ input peek= $" ifTrue: [ input next. inQuote:=true]]]. char = (Character cr) ifFalse: [temp := temp, char asString] ifTrue: [ inQuote ifFalse: [ output nextPut: temp. temp:=''. input peek = Character lf ifTrue: [input next]]]]]
I would be interested in (speed & elegance & mistakes) improvements to it.
Stephan
beginners@lists.squeakfoundation.org