William James
10/2/2007 3:12:00 PM
On Oct 2, 8:24 am, Josselin <josse...@wanadoo.fr> wrote:
> On 2007-10-02 14:46:48 +0200, William James <w_a_x_...@yahoo.com> said:
>
> > On Oct 2, 6:35 am, Josselin <josse...@wanadoo.fr> wrote:
> >> I don't use it very often, rather copying from example, but it's so
> >> useful that I should learn how to write it
> >> I'd appreciate any guru tip on how to proceed once the problem is on
> >> the paper :
>
> >> example :
>
> >> INPUT STRINGS
>
> >> 1- input can contains spaces (should be eliminated)
>
> >> 2- good patterns :
>
> >> 2a- an Integer like 99 (no limit)
> >> a > >= < <= <> != followed by an Integer like >99
>
> >>> =99 <99 <=99 <>99 !=99
>
> >> 2b- a String like: abcd abc99 99abc a99bc
>
> >> 2c- a % sign followed by a String
> >> like %abcd %abc99 %99abc %a99bc %abcd
>
> >> 2d- a String followed by a % sign
> >> like abcd% abc99% 99abc% a99bc%
>
> >> 2e- a String leading containing or ending with, one or many * sign(s)
> >> like a*bcd a**bc99 99*a*bc *a99bc a99bc* *a99bc* *a9**9b*c*
>
> >> 3-any other pattern will be considered as wrong
>
> >> OUTPUTS
>
> >> 2a -> an array [characters, Integer] like [ "<>", 99]
> >> 2b, 2c, 2d,2e -> an array [ nil, String] like [nil, abcd] or [nil,
> >> %abcd] or [nil, a99bc%] or [nil, *a9**9b*c]
>
> >> I am interesting in understanding the design process... : how should I
> >> start when designing such gsub routine ?
> >> should I state it differently on paper first ? well, any tip that can
> >> help me to build the next ones....
>
> >> thanks for your support
>
> >> joss
>
> > def foo s
> > case s
> > when /^(>|>=|<|<=|<>|!=)?(\d+)$/
> > [ $1 || "", $2.to_i ]
> > when /^(%)?[a-z\d]+(%)?$/
> > return nil if 1 != $~.captures.compact.size
> > [ nil, $& ]
> > when /^(?=.*\*)[*a-z\d]+$/
> > [ nil, $& ]
> > end
> > end
>
> > p foo( "88" )
> > p foo( "<>88" )
> > p foo( "%33" )
> > p foo( "33%" )
> > p foo( "a*9" )
> > p foo( 'bat' )
>
> thanks a lot , William, I can see how you built it.. I just have 2
> points to clarify if you don't mind
>
> 1- return nil if 1 != $~.captures.compact.size
> I don't catch up
I wrote the function so that it will return nil if the string
doesn't match your patterns. The line above is equivalent to
if 1 != $~.captures.compact.size
return nil
end
The number of succesful captures (captured by /^(%)?[a-z\d]+(%)?$/ )
must
be exactly 1; i.e., the string must begin or end with %, but not both.
>
> 2- (?=.*\*)
(?=...) is a zero-width look-ahead; it looks ahead but it doesn't
move ahead in the string. I put this here to make sure that the
string contains at least one *.
>
> otherwise I commented it .. is my understanding correct ?
>
> def foo s
> case s
I forgot about spaces. If they can only be at the start or end of the
string, use
case s.strip
> when /^(>|>=|<|<=|<>|!=)?(\d+)$/
> # start with > OR >= OR < OR <= OR <> OR != (0 or 1 time) then
> digit(0-9) n times
1 or more times.
> [ $1 || "", $2.to_i ]
> # first element or nil , second element to integer
If 1st capture is nil, use ""; else use 1st capture.
>
> when /^(%)?[a-z\d]+(%)?$/
> # start with % ( 0 or 1 time) then characters a-zA-Z 1 or n times then
> end with % ( 0 or 1 time)
> return nil if 1 != $~.captures.compact.size
> # return nil if .....
> [ nil, $& ]
> # first element nil, second element = parameter
This is a good point. Instead of $& (what was matched by the reg.ex.)
I should
have used the parameter of the function, s.
>
> when /^(?=.*\*)[*a-z\d]+$/
> # start with *( 0 or n times)...... then characters *a-zA-Z 1 or n tiems
> [ nil, $& ]
> # first element nil, second element = parameter
> end
> end