Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

String as integer #17299

Open
wants to merge 9 commits into
base: Pharo13
Choose a base branch
from
29 changes: 25 additions & 4 deletions src/Collections-Strings-Tests/StringTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -447,11 +447,12 @@ StringTest >> testAsHTMLString [
{ #category : 'tests - converting' }
StringTest >> testAsInteger [

self assert: '1796exportFixes-tkMX' asInteger equals: 1796.
self assert: 'donald' asInteger isNil.
self assert: 'abc234def567' asInteger equals: 234.
self should: [ '1796exportFixes-tkMX' asInteger ] raise: Error.
self should: [ 'donald' asInteger ] raise: Error.
self should: [ 'abc234def567' asInteger ] raise: Error.
jordanmontt marked this conversation as resolved.
Show resolved Hide resolved
self should: [ '123 4' asInteger ] raise: Error.
self assert: '-94' asInteger equals: -94.
self assert: 'foo-bar-92' asInteger equals: -92
self assert: '9432' asInteger equals: 9432
]

{ #category : 'tests' }
Expand Down Expand Up @@ -536,6 +537,16 @@ StringTest >> testAsTime [
self assert: '13' asTime asString equals: '1:00 pm'
]

{ #category : 'tests' }
StringTest >> testAsUnsignedInteger [

self should: [ 'test' asUnsignedInteger ] raise: Error.
self should: [ 'test-10test' asUnsignedInteger ] raise: Error.
self assert: '-1234567890' asUnsignedInteger equals: 1234567890.
self assert: '-12345' asUnsignedInteger equals: 12345.
self assert: '111' asUnsignedInteger equals: 111
]

{ #category : 'tests' }
StringTest >> testAsUppercase [

Expand Down Expand Up @@ -863,6 +874,16 @@ StringTest >> testExpandMacrosWithArgumentsLongText [
self assert: ('<1p>' expandMacrosWith: ('a' repeat: 100000)) size equals: 100002
]

{ #category : 'tests' }
StringTest >> testExtractIntegerPart [

self assert: '1796exportFixes-tkMX' extractIntegerPart equals: 1796.
self assert: 'donald' extractIntegerPart isNil.
self assert: 'abc234def567' extractIntegerPart equals: 234.
self assert: '-94' extractIntegerPart equals: -94.
self assert: 'foo-bar-92' extractIntegerPart equals: -92
]

{ #category : 'tests' }
StringTest >> testFindAnySubstringStartingAt [

Expand Down
21 changes: 0 additions & 21 deletions src/Collections-Strings-Tests/WideStringTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,6 @@ WideStringTest >> classToBeTested [
^ WideString
]

{ #category : 'tests - converting' }
WideStringTest >> testAsInteger [
self assert: '1796exportFixes-tkMX' asWideString asInteger equals: 1796.
self assert: 'donald' asWideString asInteger isNil.
self assert: 'abc234def567' asWideString asInteger equals: 234.
self assert: '-94' asWideString asInteger equals: -94.
self assert: 'foo-bar-92' asWideString asInteger equals: -92.

self assert: '1796exportFixes-tkMX' asWideString asSignedInteger equals: 1796.
self assert: 'donald' asWideString asSignedInteger isNil.
self assert: 'abc234def567' asWideString asSignedInteger equals: 234.
self assert: '-94' asWideString asSignedInteger equals: -94.
self assert: 'foo-bar-92' asWideString asSignedInteger equals: -92.

self assert: '1796exportFixes-tkMX' asWideString asUnsignedInteger equals: 1796.
self assert: 'donald' asWideString asUnsignedInteger isNil.
self assert: 'abc234def567' asWideString asUnsignedInteger equals: 234.
self assert: '-94' asWideString asUnsignedInteger equals: 94.
self assert: 'foo-bar-92' asWideString asUnsignedInteger equals: 92
]

{ #category : 'testing' }
WideStringTest >> testAtPut [
"Non regression test for http://bugs.squeak.org/view.php?id=6998"
Expand Down
52 changes: 30 additions & 22 deletions src/Collections-Strings/String.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -686,13 +686,16 @@ String >> asHex [

{ #category : 'converting' }
String >> asInteger [
"Return the integer present in the receiver, or nil. In case of float, returns the integer part."
"Return the integer present in the receiver. The receiver has to be a valid integer."

"'1' asInteger >>> 1"
"'-1' asInteger >>> -1"
"'10' asInteger >>> 10"
"'a' asInteger >>> nil"
"'1.234' asInteger >>> 1"
^self asSignedInteger

(NumberParser isNumber: self) ifFalse: [
self error: 'The string ', self surroundedBySingleQuotes , ' is not a valid integer' ].
^ NumberParser parse: self
]

{ #category : 'converting' }
Expand Down Expand Up @@ -731,19 +734,6 @@ String >> asPluralBasedOn: aNumberOrCollection [
ifFalse: [self, 's']
]

{ #category : 'converting' }
String >> asSignedInteger [
"Returns the first signed integer it can find or nil."

| start stream |
start := self findFirst: [:char | char isDigit].
start isZero ifTrue: [^ nil].
stream := self readStream position: start - 1.
((stream position ~= 0) and: [stream peekBack = $-])
ifTrue: [stream back].
^ Integer readFrom: stream
]

{ #category : 'converting' }
String >> asString [
"Answer this string."
Expand All @@ -766,12 +756,9 @@ String >> asTime [

{ #category : 'converting' }
String >> asUnsignedInteger [
"Returns the first integer it can find or nil."
| start stream |
start := self findFirst: [ :char | char isDigit ].
start isZero ifTrue: [ ^ nil ].
stream := self readStream position: start - 1.
^ Integer readFrom: stream


^ self asInteger abs
]

{ #category : 'converting' }
Expand Down Expand Up @@ -1361,6 +1348,27 @@ String >> expandMacrosWithArguments: anArray [
ifFalse: [ char ]) ] ] ]
]

{ #category : 'converting' }
String >> extractIntegerPart [
"Returns the first signed integer it can find or nil."

"'1' extractIntegerPart >>> 1"
"'-1' extractIntegerPart >>> -1"
"'10qwe' extractIntegerPart >>> 10"
"'a10q' extractIntegerPart >>> 10"
"'a10q22' extractIntegerPart >>> 10"
"'1.234' extractIntegerPart >>> 1"
"'a' extractIntegerPart >>> nil"

| start stream |
start := self findFirst: [ :char | char isDigit ].
start isZero ifTrue: [ ^ nil ].
stream := self readStream position: start - 1.
(stream position ~= 0 and: [ stream peekBack = $- ]) ifTrue: [
stream back ].
^ Integer readFrom: stream
]

{ #category : 'finding/searching' }
String >> findAnySubstring: aCollection startingAt: start [
"Answer the index where an element of aCollection begins. If none are found, answer size + 1. aCollection is an Array of Strings or Characters."
Expand Down
13 changes: 13 additions & 0 deletions src/Deprecated13/String.extension.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Extension { #name : 'String' }

{ #category : '*Deprecated13' }
String >> asSignedInteger [
"Returns the first signed integer it can find or nil."

self
deprecated:
'Use #asInteger to convert to a valid integer. If you want to extract the integer part, use #extractIntegerPart'
transformWith:
'`@receiver asSignedInteger' -> '`@receiver extractIntegerPart'.
^ self extractIntegerPart
]
28 changes: 12 additions & 16 deletions src/Metacello-Core/MetacelloSemanticVersionNumber.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -199,22 +199,18 @@ MetacelloSemanticVersionNumber class >> fromString: aString forPattern: forPatte

{ #category : 'private' }
MetacelloSemanticVersionNumber class >> integerFromString: aString [
aString
detect: [ :char | char isDigit not ]
ifNone: [
| integer |
integer := aString asInteger.
((aString at: 1) = $0 and: [ aString size > 1 ])
ifTrue: [
self
error:
'invalid version number: normal version component must not have leading 0s'
, aString asString ].
^ integer ].
self
error:
'invalid version number: normal version component must be integer '
, aString asString

aString detect: [ :char | char isDigit not ] ifNone: [
| integer |
integer := aString extractIntegerPart.
((aString at: 1) = $0 and: [ aString size > 1 ]) ifTrue: [
self error:
'invalid version number: normal version component must not have leading 0s'
, aString asString ].
^ integer ].
self error:
'invalid version number: normal version component must be integer '
, aString asString
]

{ #category : 'private' }
Expand Down
9 changes: 5 additions & 4 deletions src/Ombu/OmBlock.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ OmBlock >> atLocalName: aString ifPresent: presentBlockClosure ifAbsent: absentB
| index |
self checkIfMustRefreshBlock.

index := aString asInteger - self firstLocalNameAsInteger + 1.
index := aString extractIntegerPart - self firstLocalNameAsInteger + 1.

^ index > positions size
ifTrue: [ absentBlockClosure value ]
ifFalse: [presentBlockClosure value: (positions at: index) ]
ifTrue: [ absentBlockClosure value ]
ifFalse: [ presentBlockClosure value: (positions at: index) ]
]

{ #category : 'refreshing' }
Expand All @@ -58,7 +58,8 @@ OmBlock >> firstEntryReference [

{ #category : 'accessing' }
OmBlock >> firstLocalNameAsInteger [
^ self firstEntryReference localName asInteger

^ self firstEntryReference localName extractIntegerPart
]

{ #category : 'initialization' }
Expand Down
10 changes: 5 additions & 5 deletions src/Ombu/OmBlockFileStore.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ OmBlockFileStore >> initialize [
{ #category : 'accessing' }
OmBlockFileStore >> readEntryForLocalName: aString ifPresent: presentBlockClosure ifAbsent: absentBlockClosure [

^ (self blockForLocalNameAsInteger: aString asInteger)
atLocalName: aString
ifPresent: [ :position |
presentBlockClosure value: (self nextEntryFromPosition: position) ]
ifAbsent: absentBlockClosure
^ (self blockForLocalNameAsInteger: aString extractIntegerPart)
atLocalName: aString
ifPresent: [ :position |
presentBlockClosure value: (self nextEntryFromPosition: position) ]
ifAbsent: absentBlockClosure
]

{ #category : 'refreshing' }
Expand Down
11 changes: 6 additions & 5 deletions src/Ombu/OmFileStore.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -415,16 +415,17 @@ OmFileStore >> refreshEntryPositionsByLocalNameStartingAt: firstStreamPosition s
(+ would need special care of WideStrings)"

| localNameAsInteger |
localNameAsInteger := initialLocalName asInteger.
localNameAsInteger := initialLocalName extractIntegerPart.

self readEntriesWith: [:readStream |
self readEntriesWith: [ :readStream |
readStream position: firstStreamPosition.
self newEntryReader
stream: readStream;
entryPositionsDo: [ :entryPosition |
entryPositionsByLocalName at: localNameAsInteger asString put: entryPosition.
localNameAsInteger := localNameAsInteger + 1 ].
]
entryPositionsByLocalName
at: localNameAsInteger asString
put: entryPosition.
localNameAsInteger := localNameAsInteger + 1 ] ]
]

{ #category : 'accessing' }
Expand Down
6 changes: 3 additions & 3 deletions src/Ombu/OmMemoryStore.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ OmMemoryStore >> entriesDo: aBlockClosure [
OmMemoryStore >> entryFor: aReference ifPresent: presentBlockClosure ifAbsent: absentBlockClosure [

| entry |
(aReference isNull or: [ aReference globalName ~= self globalName])
(aReference isNull or: [ aReference globalName ~= self globalName ])
ifTrue: [ ^ absentBlockClosure value ].

entry := entries
at: aReference localName asInteger
ifAbsent: [ ^ absentBlockClosure value ].
at: aReference localName extractIntegerPart
ifAbsent: [ ^ absentBlockClosure value ].

^ presentBlockClosure cull: entry
]
Expand Down
2 changes: 1 addition & 1 deletion src/Reflectivity/Context.extension.st
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Context >> currentBytecode: currentBytecode equalsToNewBytecode: newBytecode wit
ifFalse: [ false ]
ifTrue: [
| currentJumpPc newJumpPc currentJumpBytecode newJumpBytecode |
currentJumpPc := (currentSplitDescription at: 2) asInteger.
currentJumpPc := (currentSplitDescription at: 2) extractIntegerPart.
newJumpPc := (newSplitDescription at: 2) asInteger.
currentJumpBytecode := currentSymbolicBytecodes
detect: [ :csb |
Expand Down
8 changes: 4 additions & 4 deletions src/System-Support/SystemVersion.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ SystemVersion class >> setMajor: major minor: minor patch: patch suffix: aString
{ #category : 'accessing - properties' }
SystemVersion >> build [

^ build asInteger
^ build extractIntegerPart
]

{ #category : 'accessing - properties' }
Expand Down Expand Up @@ -242,7 +242,7 @@ SystemVersion >> initialize [
SystemVersion >> major [
"Answer the major number of a version. 1 in '1.2'"

^ major asInteger
^ major extractIntegerPart
]

{ #category : 'accessing - properties' }
Expand Down Expand Up @@ -290,7 +290,7 @@ SystemVersion >> majorMinorVersion [
SystemVersion >> minor [
"Answer the minor number of a version. 2 in '1.2'"

^ minor asInteger
^ minor extractIntegerPart
]

{ #category : 'accessing - properties' }
Expand All @@ -303,7 +303,7 @@ SystemVersion >> minor: anInteger [
{ #category : 'accessing' }
SystemVersion >> patch [

^ patch asInteger
^ patch extractIntegerPart
]

{ #category : 'accessing' }
Expand Down
14 changes: 7 additions & 7 deletions src/System-Time/DateAndTime.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -176,22 +176,22 @@ DateAndTime class >> fuzzyReadFrom: aStream [


aStream peek = $- ifTrue: [ aStream next. bc := -1] ifFalse: [bc := 1].
year := (aStream upTo: $-) asInteger * bc.
month := (aStream upTo: $-) asInteger ifNil: [1].
day := (aStream upTo: $T) asInteger ifNil: [1].
hour := (aStream upTo: $:) asInteger ifNil: [0].
year := (aStream upTo: $-) extractIntegerPart * bc.
month := (aStream upTo: $-) extractIntegerPart ifNil: [1].
day := (aStream upTo: $T) extractIntegerPart ifNil: [1].
hour := (aStream upTo: $:) extractIntegerPart ifNil: [0].
buffer := '00:' copy. ch := nil.
minute := buffer writeStream.
[ aStream atEnd | (ch = $:) | (ch = $+) | (ch = $-) ]
whileFalse: [ ch := minute nextPut: aStream next. ].
(ch isNil or: [ch isDigit]) ifTrue: [ ch := $: ].
minute := (buffer readStream upTo: ch) asInteger.
minute := (buffer readStream upTo: ch) extractIntegerPart.
buffer := '00.' copy.
second := buffer writeStream.
[ aStream atEnd | (ch = $.) | (ch = $+) | (ch = $-) ]
whileFalse: [ ch := second nextPut: aStream next. ].
(ch isNil or: [ch isDigit]) ifTrue: [ ch := $. ].
second := (buffer readStream upTo: ch) asInteger.
second := (buffer readStream upTo: ch) extractIntegerPart.
buffer := '000000000' copy.
(ch = $.) ifTrue: [
nanos := buffer writeStream.
Expand All @@ -200,7 +200,7 @@ DateAndTime class >> fuzzyReadFrom: aStream [
(ch isNil or: [ch isDigit]) ifTrue: [ ch := $+ ].
].

nanos := buffer asInteger.
nanos := buffer extractIntegerPart.
aStream atEnd
ifTrue: [ offset := Duration zero ]
ifFalse: [ch := aStream next.
Expand Down
2 changes: 1 addition & 1 deletion src/System-Time/DateParser.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ DateParser >> parse: aTimeUnitName [
DateParser >> parse: timeUnitName expectedSize: anInteger [
| extractedString result |
extractedString := inputStream next: anInteger.
result := extractedString asInteger.
result := extractedString extractIntegerPart.
(result isNil or: [ extractedString size ~= anInteger ])
ifTrue: [ DateError signal: ' Expect a two digit ', timeUnitName, ', got ', extractedString ].
^ result
Expand Down
Loading