[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Help-smalltalk] [rfc] regex rewrite
From: |
Paolo Bonzini |
Subject: |
Re: [Help-smalltalk] [rfc] regex rewrite |
Date: |
Tue, 31 May 2005 09:34:17 +0200 |
User-agent: |
Mozilla Thunderbird 0.9 (Macintosh/20041103) |
I also think it would be more useful if =~ returned MatchResult/nil
instead of true/false.
There's #searchRegex: for that. The "=~" name seemed more like a
boolean query to me.
There's #matchRegex: '.*whatever.*' for that :)
Oh, for that matter there's also (foo indexOfRegex: 'aaa') > 0. :-)
Both Perl and Ruby return values that can be interpreted as true/false
from =~, but both of them also capture the matched expression and
sub-expressions into variables. We don't have that possibility, so I
think =~ should work harder.
That's fine with me, if we add #matched, #ifMatched:, etc. methods to
RegexResults as in your previous suggestion, that avoid the unintuitive
#isNil. To have a bit more efficiency, the RegexResults object for
not-matched is a singleton; this means that RegexResults is now at the
head of a small class hierarchy comprising MatchingRegexResults, and
FailedMatchRegexResults.
Paolo
--- orig/examples/regex.st
+++ mod/examples/regex.st
@@ -61,20 +61,104 @@
!
Object subclass: #RegexResults
+ instanceVariableNames: ''
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'Regex'
+!
+
+RegexResults subclass: #MatchingRegexResults
instanceVariableNames: 'subject from to registers match cache'
classVariableNames: ''
poolDictionaries: ''
category: 'Regex'
!
-!RegexResults methodsFor: 'accessing'!
+RegexResults subclass: #FailedMatchRegexResults
+ instanceVariableNames: ''
+ classVariableNames: 'NotMatched'
+ poolDictionaries: ''
+ category: 'Regex'
+!
+
+!FailedMatchRegexResults class methodsFor: 'private'!
-subject
- ^subject!
+initialize
+ NotMatched := self new
+!
+
+notMatched
+ ^NotMatched
+! !
+
+!FailedMatchRegexResults methodsFor: 'testing'!
+
+matched
+ ^false
+!
+
+ifMatched: oneArgBlock ifNotMatched: zeroArgBlock
+ ^zeroArgBlock value
+!
+
+ifNotMatched: zeroArgBlock ifMatched: oneArgBlock
+ ^zeroArgBlock value
+!
+
+ifNotMatched: zeroArgBlock
+ ^zeroArgBlock value
+!
+
+ifMatched: oneArgBlock
+ ^nil
+! !
+
+!MatchingRegexResults methodsFor: 'printing'!
+
+printOn: aStream
+ "Print a represention of the receiver on aStream."
+ | ch |
+ aStream
+ nextPutAll: self class name;
+ nextPut: $:;
+ print: self match.
+ ch := $(.
+ 1 to: self size do: [ :each |
+ aStream nextPut: ch; print: (self at: each).
+ ].
+ self size > 0 ifTrue: [ aStream nextPut: $) ].
+! !
+
+!MatchingRegexResults methodsFor: 'testing'!
+
+matched
+ ^true
+!
+
+ifMatched: oneArgBlock ifNotMatched: zeroArgBlock
+ ^oneArgBlock value: self
+!
+
+ifNotMatched: zeroArgBlock ifMatched: oneArgBlock
+ ^oneArgBlock value: self
+!
+
+ifNotMatched: zeroArgBlock
+ ^nil
+!
+
+ifMatched: oneArgBlock
+ ^oneArgBlock value: self
+! !
+
+!MatchingRegexResults methodsFor: 'accessing'!
size
^registers size!
+subject
+ ^subject!
+
from
^from!
@@ -121,7 +205,7 @@
size
^registers size! !
-!RegexResults methodsFor: 'private'!
+!MatchingRegexResults methodsFor: 'private'!
initialize: regs subject: aString
from := regs matchBeg.
@@ -132,7 +216,7 @@
end := (regs endAt: i).
end < 0 ifTrue: [ nil ] ifFalse: [ beg to: end ] ].
cache := Array new: registers size.
- subject := aString!
+ subject := aString! !
" --- external function definitions --- "
@@ -249,40 +333,69 @@
!String methodsFor: 'regex'!
-=~ regexString
- "Answer whether an occurrence of the regex is present in the receiver"
- | regs gotIt |
- regs := self searchRegexInternal: regexString from: 1 to: self size.
- gotIt := regs matchBeg > 0.
- regs free.
- ^gotIt
-!
-
asRegex
"Answer the receiver, converted to a Regex object."
^Regex fromString: self
!
+=~ pattern
+ "Answer a RegexResults object for matching the receiver against
+ the Regex or String object pattern."
+ | regs |
+ regs := self searchRegexInternal: pattern from: 1 to: self size.
+ ^regs matchBeg = -1
+ ifTrue: [
+ regs free.
+ FailedMatchRegexResults notMatched
+ ]
+ ifFalse: [
+ [ MatchingRegexResults new initialize: regs subject: self ]
+ ensure: [ regs free ]
+ ]
+!
+
searchRegex: pattern
+ "A synonym for #=~"
| regs |
regs := self searchRegexInternal: pattern from: 1 to: self size.
- regs matchBeg = -1 ifTrue: [ regs free. ^nil ].
- ^[ RegexResults new initialize: regs subject: self ]
- ensure: [ regs free ]!
+ ^regs matchBeg = -1
+ ifTrue: [
+ regs free.
+ FailedMatchRegexResults notMatched
+ ]
+ ifFalse: [
+ [ MatchingRegexResults new initialize: regs subject: self ]
+ ensure: [ regs free ]
+ ]
+!
searchRegex: pattern startingAt: anIndex
| regs |
regs := self searchRegexInternal: pattern from: anIndex to: self size.
- regs matchBeg = -1 ifTrue: [ regs free. ^nil ].
- ^[ RegexResults new initialize: regs subject: self ]
- ensure: [ regs free ]!
+ ^regs matchBeg = -1
+ ifTrue: [
+ regs free.
+ FailedMatchRegexResults notMatched
+ ]
+ ifFalse: [
+ [ MatchingRegexResults new initialize: regs subject: self ]
+ ensure: [ regs free ]
+ ]
+!
searchRegex: pattern from: from to: to
| regs |
regs := self searchRegexInternal: pattern from: from to: to.
- regs matchBeg = -1 ifTrue: [ regs free. ^nil ].
- ^[ RegexResults new initialize: regs subject: self ]
- ensure: [ regs free ]!
+ ^regs matchBeg = -1
+ ifTrue: [
+ regs free.
+ FailedMatchRegexResults notMatched
+ ]
+ ifFalse: [
+ [ MatchingRegexResults new initialize: regs subject: self ]
+ ensure: [ regs free ]
+ ]
+!
indexOfRegex: regexString ifAbsent: excBlock
"Answer whether an occurrence of the regex is present in the receiver"
@@ -431,7 +544,6 @@
idx := from.
[
regs := self searchRegex: regex from: idx to: to.
- beg >= 1
regs notNil
] whileTrue: [
beg := regs from.
@@ -511,3 +623,4 @@
^self tokenize: '[\n\t ]+' from: 1 to: self size
! !
+FailedMatchRegexResults initialize!