[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

String splitting problem

Saladin Mundi

12/14/2007 2:03:00 PM

hey guys

I'm trying to split an string (which contains various method calls).
The result of the splitting of the string should be an array (or
something like that) which contains a sequence which an interpreter
would have called the methods.
Example

class X
def test(input)
...
end
end

x.new.test("z.methodx(z.methody(),z.methodz(z.methodx))")


If I pass "z.methodx(z.methody(),z.methodz(z.methodx))" there should be
afterwards an arry like this:

[0] -> var1 = z.methody()
[1] -> var2 = z.methodx
[2] -> var3 = z.methodz(var2)
[3] -> z.methodx(var1,var3)

so the call(s on different methods) given by an input string shall be
extracted into the real execution sequence like an interpreter would
excecute this string it.

I hope you can help me with my problem.
--
Posted via http://www.ruby-....

4 Answers

Joe

12/15/2007 12:44:00 AM

0

hey,

I didn't test this too well, but it works for your string. I doubt
it's the most clever way to do it, but it should get the job done.

stack = Array.new
input = "z.methodx(z.methody(),z.methodz(z.methodx))"

last = 0
count = 0

while last < input.length
cur = input.index(/[\)\(,]/, last)
if cur then
b = input[cur,1]
if (/[\(,]/.match(input[last-1,1]) &&
/[\),]/.match(b)) && cur-last > 1 then
count += 1
puts count.to_s + " " + input[last, cur-last]
stack[-1] += count.to_s
end

case b
when '('
stack.push(input[last, cur-last] + "(")
when ')'
count += 1
puts count.to_s + " " + stack.pop + ")"
stack[-1] += count.to_s
when ','
stack[-1] += ','
end

last = cur+1
end
end

Joe

On Dec 14, 2007 9:03 AM, Saladin Mundi <saladin.mundi@gmx.de> wrote:
> hey guys
>
> I'm trying to split an string (which contains various method calls).
> The result of the splitting of the string should be an array (or
> something like that) which contains a sequence which an interpreter
> would have called the methods.
> Example
>
> class X
> def test(input)
> ...
> end
> end
>
> x.new.test("z.methodx(z.methody(),z.methodz(z.methodx))")
>
>
> If I pass "z.methodx(z.methody(),z.methodz(z.methodx))" there should be
> afterwards an arry like this:
>
> [0] -> var1 = z.methody()
> [1] -> var2 = z.methodx
> [2] -> var3 = z.methodz(var2)
> [3] -> z.methodx(var1,var3)
>
> so the call(s on different methods) given by an input string shall be
> extracted into the real execution sequence like an interpreter would
> excecute this string it.
>
> I hope you can help me with my problem.
> --
> Posted via http://www.ruby-....
>
>

Joe

12/15/2007 1:37:00 AM

0

I made a small mistake

change
stack[-1] += count.to_s
to
stack[-1] += count.to_s if stack[-1]

On Dec 14, 2007 7:44 PM, Joe <qbproger@gmail.com> wrote:
>
> hey,
>
> I didn't test this too well, but it works for your string. I doubt
> it's the most clever way to do it, but it should get the job done.
>
> stack = Array.new
> input = "z.methodx(z.methody(),z.methodz(z.methodx))"
>
> last = 0
> count = 0
>
> while last < input.length
> cur = input.index(/[\)\(,]/, last)
> if cur then
> b = input[cur,1]
> if (/[\(,]/.match(input[last-1,1]) &&
> /[\),]/.match(b)) && cur-last > 1 then
> count += 1
> puts count.to_s + " " + input[last, cur-last]
> stack[-1] += count.to_s
> end
>
> case b
> when '('
> stack.push(input[last, cur-last] + "(")
> when ')'
> count += 1
> puts count.to_s + " " + stack.pop + ")"
> stack[-1] += count.to_s
> when ','
> stack[-1] += ','
> end
>
> last = cur+1
> end
> end
>
> Joe
>
> On Dec 14, 2007 9:03 AM, Saladin Mundi <saladin.mundi@gmx.de> wrote:
>
> > hey guys
> >
> > I'm trying to split an string (which contains various method calls).
> > The result of the splitting of the string should be an array (or
> > something like that) which contains a sequence which an interpreter
> > would have called the methods.
> > Example
> >
> > class X
> > def test(input)
> > ...
> > end
> > end
> >
> > x.new.test("z.methodx(z.methody(),z.methodz(z.methodx))")
> >
> >
> > If I pass "z.methodx(z.methody(),z.methodz(z.methodx))" there should be
> > afterwards an arry like this:
> >
> > [0] -> var1 = z.methody()
> > [1] -> var2 = z.methodx
> > [2] -> var3 = z.methodz(var2)
> > [3] -> z.methodx(var1,var3)
> >
> > so the call(s on different methods) given by an input string shall be
> > extracted into the real execution sequence like an interpreter would
> > excecute this string it.
> >
> > I hope you can help me with my problem.
> > --
> > Posted via http://www.ruby-....
> >
> >
>
>

Phrogz

12/15/2007 4:54:00 AM

0

On Dec 14, 7:03 am, Saladin Mundi <saladin.mu...@gmx.de> wrote:
> hey guys
>
> I'm trying to split an string (which contains various method calls).
> The result of the splitting of the string should be an array (or
> something like that) which contains a sequence which an interpreter
> would have called the methods.
> Example
>
> class X
> def test(input)
> ...
> end
> end
>
> x.new.test("z.methodx(z.methody(),z.methodz(z.methodx))")
>
> If I pass "z.methodx(z.methody(),z.methodz(z.methodx))" there should be
> afterwards an arry like this:
>
> [0] -> var1 = z.methody()
> [1] -> var2 = z.methodx
> [2] -> var3 = z.methodz(var2)
> [3] -> z.methodx(var1,var3)
>
> so the call(s on different methods) given by an input string shall be
> extracted into the real execution sequence like an interpreter would
> excecute this string it.

On Dec 14, 7:03 am, Saladin Mundi <saladin.mu...@gmx.de> wrote:
> hey guys
>
> I'm trying to split an string (which contains various method calls).
> The result of the splitting of the string should be an array (or
> something like that) which contains a sequence which an interpreter
> would have called the methods.
> Example
>
> class X
> def test(input)
> ...
> end
> end
>
> x.new.test("z.methodx(z.methody(),z.methodz(z.methodx))")
>
> If I pass "z.methodx(z.methody(),z.methodz(z.methodx))" there should be
> afterwards an arry like this:
>
> [0] -> var1 = z.methody()
> [1] -> var2 = z.methodx
> [2] -> var3 = z.methodz(var2)
> [3] -> z.methodx(var1,var3)
>
> so the call(s on different methods) given by an input string shall be
> extracted into the real execution sequence like an interpreter would
> excecute this string it.
>
> I hope you can help me with my problem.

Wow, that was harder than I expected. The big issue was parsing nested
commands; I couldn't use regexps, so I had to create a little stack-
based parser. Thanks for the fun challenge.

In summary:

puts
MethodMunger.variable_stack( "z.methodx(z.methody(),z.methodz(z.methodx))" )
#=> var0 = z.methodx()
#=> var1 = z.methody()
#=> var2 = z.methodz( var0 )
#=> z.methodx( var1, var2 )


And now, the code, all unit tested:

# Put MWI in the core! enum_for is retarded!
module Enumerable
def map_with_index
idx = -1
map{ |v| yield v,idx+=1 }
end
end

module MethodMunger
require 'strscan'

# MethodMunger.parse_method( "z.foo( bar( x ), y )" )
# #=> {
# #=> :name=>"z.foo",
# #=> :args=>[
# #=> {
# #=> :name=>"bar",
# #=> :args=>[
# #=> {:name=>"x"}
# #=> ]
# #=> },
# #=> {:name=>"y"}
# #=> ]
# #=> }
def self.parse_method( source )
stack = [ ]
current_method = nil
mode = :prepare_method

scanner = StringScanner.new( source )
until scanner.eos?
case mode
when :prepare_method
new_method = {}
current_method = new_method
mode = :find_content

when :add_argument
new_method = {}
(current_method[:args] ||= []) << new_method
stack << current_method
current_method = new_method
mode = :find_content

when :find_content
if chunk = scanner.scan( /[\w.]+/ )
current_method[ :name ] = chunk

elsif chunk = scanner.scan( /\(\s*/ )
mode = :add_argument

elsif chunk = scanner.scan( /\s*,\s*/ )
current_method.delete(:args) if current_method[:args] ==
[{}]
current_method = stack.pop
mode = :add_argument

elsif chunk = scanner.scan( /\s*\)/ )
current_method.delete(:args) if current_method[:args] ==
[{}]
current_method = stack.pop

end
end
end

current_method.delete(:args) if current_method[:args] ==
[{}]
current_method
end

def self.variable_stack( source )
method = parse_method( source )
variable_stack_from_parse( method )
end

private
def self.variable_stack_from_parse( method )
if method[:args]
lines = []
params = method[:args].map{ |arg|
var_lines = variable_stack_from_parse( arg )
arg_close = var_lines.pop
lines.concat( var_lines )
arg_close
}
total_lines = lines.length
params.each_with_index{ |var,i|
lines << "var#{i+total_lines} = #{var}"
}
lines << "#{method[:name]}( #{
params.map_with_index{ |v,i|
"var#{i + total_lines}"
}.join(', ')
} )"
else
["#{method[:name]}()"]
end
end
end

puts
MethodMunger.variable_stack( "z.methodx(z.methody(),z.methodz(z.methodx))" )
#=> var0 = z.methodx()
#=> var1 = z.methody()
#=> var2 = z.methodz( var0 )
#=> z.methodx( var1, var2 )

if __FILE__==$0
require 'test/unit'
class TestParser < Test::Unit::TestCase
def testa_no_arguments
result = MethodMunger.parse_method "z.go( )"
assert_equal( {
:name=>"z.go"
}, result )

result = MethodMunger.parse_method "z.go()"
assert_equal( {
:name=>"z.go"
}, result )

result = MethodMunger.parse_method "z.go"
assert_equal( {
:name=>"z.go"
}, result )
end
def testb_no_nesting
result = MethodMunger.parse_method "z.go( x )"
assert_equal( {
:name=>"z.go",
:args=>[
{ :name=>"x" }
]
}, result )

result = MethodMunger.parse_method "z.go( x, y )"
assert_equal( {
:name=>"z.go",
:args=>[
{ :name=>"x" },
{ :name=>"y" },
]
}, result )

result = MethodMunger.parse_method "z.go( w, x, y )"
assert_equal( {
:name=>"z.go",
:args=>[
{ :name=>"w" },
{ :name=>"x" },
{ :name=>"y" },
]
}, result )
end
def testc_nesting
result = MethodMunger.parse_method "z.go( x( y ) )"
assert_equal( {
:name=>"z.go",
:args=>[
{
:name=>"x",
:args=>[
{ :name=>"y" }
]
},
]
}, result )

result = MethodMunger.parse_method "z.go( x( y, w ) )"
assert_equal( {
:name=>"z.go",
:args=>[
{
:name=>"x",
:args=>[
{ :name=>"y" },
{ :name=>"w" },
]
},
]
}, result )

result = MethodMunger.parse_method "z.go( foo( bar ),x( y,
w ) )"
assert_equal( {
:name=>"z.go",
:args=>[
{
:name=>"foo",
:args=>[
{ :name=>"bar" },
]
},
{
:name=>"x",
:args=>[
{ :name=>"y" },
{ :name=>"w" },
]
},
]
}, result )

end
end
class TestMunger < Test::Unit::TestCase
def test_a_no_args
result = MethodMunger.variable_stack "z.go()"
assert_equal( ["z.go()"], result )

result = MethodMunger.variable_stack "z.go( )"
assert_equal( ["z.go()"], result )

result = MethodMunger.variable_stack "z.go"
assert_equal( ["z.go()"], result )
end
def test_b_one_arg
result = MethodMunger.variable_stack "z.go(y.foo)"
assert_equal( ["var0 = y.foo()","z.go( var0 )"], result )

result = MethodMunger.variable_stack "z.go( y.foo( ) )"
assert_equal( ["var0 = y.foo()","z.go( var0 )"], result )
end
def test_c_multi_args
result = MethodMunger.variable_stack "z.go(y.foo,x.bar)"
assert_equal( [
"var0 = y.foo()",
"var1 = x.bar()",
"z.go( var0, var1 )"
], result )

result = MethodMunger.variable_stack "z.go( y.foo(), x.bar() )"
assert_equal( [
"var0 = y.foo()",
"var1 = x.bar()",
"z.go( var0, var1 )"
], result )
end
def test_d_nest_singles
result = MethodMunger.variable_stack "z.go( y.foo( x.bar ) )"
assert_equal( [
"var0 = x.bar()",
"var1 = y.foo( var0 )",
"z.go( var1 )"
], result )

result = MethodMunger.variable_stack
"z.go( y.foo( x.bar( w.jim ) ) )"
assert_equal( [
"var0 = w.jim()",
"var1 = x.bar( var0 )",
"var2 = y.foo( var1 )",
"z.go( var2 )"
], result )
end
def test_e_nest_more
result = MethodMunger.variable_stack "z.go( y.foo( x.bar,
w.jim ) )"
assert_equal( [
"var0 = x.bar()",
"var1 = w.jim()",
"var2 = y.foo( var0, var1 )",
"z.go( var2 )"
], result )
end
end
end



Saladin Mundi

12/17/2007 12:30:00 PM

0

thank you for all of your great code. I'll have a close look on it and
check if its similar to what I had thought of :)

thanks again!
--
Posted via http://www.ruby-....