From: Kaspar Schiess Date: 2004-10-14T20:50:00+09:00 Subject: Re: [nuby] shell-like substitution in a string --------------080202040905030102040008 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hello Lionel, That was quite a quiz you asked us ;) I have a solution using only 'regular' regular expressions, the one in 1.8.1. Thus: this solution works without oniguruma. I work around the lookbehind trouble by appending three spaces in front of the string. I am sure this solution is hideously complicated and can be improoved. Anyone ? Here's the output: ~ bluna ${var\}weird} ~ bluna weird substitute ~ sh ${tool} -o ${target} -L${libpath} -l${lib} ${source} ~ sh gcc -o test.exe -L/usr/lib -lopengl render.c ~ \${var} ~ \${var} ~ \\${var} ~ \\rvar ~ $\${var} ~ $\${var} ~ $\$${var} ~ $\$rvar with an env of ~ env = { 'var\}weird' => 'weird substitute', 'var' => 'rvar', 'tool' => 'gcc', 'target' => 'test.exe', 'libpath' => '/usr/lib', 'lib' => 'opengl', 'source' => 'render.c' ~ } Hope this hits your nerv, kaspar -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.4 (MingW32) Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFBbmnPFifl4CA0ImQRAjF/AJ4oweuSNuxknxcslsv0f3S9GFiebACfXO7B GYygYzZW0Co4z5S2na7y5Os= =wcON -----END PGP SIGNATURE----- --------------080202040905030102040008 Content-Type: text/plain; name="interpolation.rb" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="interpolation.rb" tests = [] tests << 'bluna ${var\\}weird}' tests << 'sh ${tool} -o ${target} -L${libpath} -l${lib} ${source}' tests << '\\${var}' tests << '\\\\${var}' tests << '$\${var}' tests << '$\$${var}' env = { 'var\}weird' => 'weird substitute', 'var' => 'rvar', 'tool' => 'gcc', 'target' => 'test.exe', 'libpath' => '/usr/lib', 'lib' => 'opengl', 'source' => 'render.c' } class ShellExpander REString = / ^ (?: \\ . | [^\\$] | \$ \\ . | \$ [^\\{] ){3,} \$ \{ ( (?: \\ . | [^\\}] )* ) } /x def initialize env={} @env = env end # call-seq: # #expand( str ) => str def expand str for_each_shell_expansion_in str do |var| @env[var] end end def for_each_shell_expansion_in str tomatch = str replacements = [] offset = 0 while str.length > 0 tomatch = ' '*3 + tomatch offset -= 3 md = REString.match tomatch break unless md replacement = yield( md[1] ) i, j = offset+md.begin(1), offset+md.end(1) replacements << [i, j, replacement] if replacement offset += md.pre_match.length + md[0].length tomatch = md.post_match end offset = 0 replacements.each do |from, to, rep| str[ (offset+from-2)...(offset+to+1) ] = rep offset += rep.length - (to-from+3) end str end end expander = ShellExpander.new env tests.each do |str| puts puts str puts expander.expand(str) end --------------080202040905030102040008--