help-smalltalk
[Top][All Lists]
Advanced

[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!

reply via email to

[Prev in Thread] Current Thread [Next in Thread]