Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Re: String expansion script

by Tanktalus (Canon)
on Feb 17, 2005 at 23:53 UTC ( [id://432143]=note: print w/replies, xml ) Need Help??


in reply to String expansion script

I just want to thank you - being able to read this thread has saved me hours of work. Or cost me hours. Depends on how you look at it. I spent about 3 hours trying to get a similar version to work, and it finally does now. Hopefully this gives me such a simplified API to doing what I am trying to do that it will save me (and my cow-orkers) enough time to justify that... Even if it doesn't, it's a cool API to work with. :-)

Here it is - I've co-opted the colon for a shell-like experience. However, if you want to provide a function that maps ".." or "," or whatever you want, you can go ahead. My requirements state that () and {} are both valid token markers, but you can do whatever you want with it. (I'm hoping to remove the ambiguity later, but I'm stuck with it for now.)

Also - in my case, it's possible to come up with duplication (partly because of the shell-likeness, if you're using it), so I came up with a method to remove duplicates while preserving order. That order part isn't well-tested, so anyone noticing anything amiss there would be appreciated :-)

=item expand_string Expands a string to possibly a set of strings. Inputs: =over 4 =item * String to expand. =item * Function used to look up the variable. The function will be passed th +e variable to be interpolated in using $_. The function should return a list of +replacement values. The function may set any return value to undef to signify that the var +iable should be left intact and unexpanded. An empty string signifies removal of the variable in +its entirety. And returning an array will cause the whole expand_string function to +return each possible item as an array. This allows you to pass in a single string + to expand into a plethora of output strings all at once. The default function is below. It is recommended that the given funct +ion call the default function in cases where it cannot resolve the variable. The d +efault function will die with an error if it cannot resolve the variable which may be +caught with eval. =back The variable may have modifiers: (variable:+foo) This means that if variable is non-zero length, use "foo" instead. If + the variable expands to nothing (or undef), use that instead (blank, or leave the v +ariable unchanged as appropriate). (variable:-foo) This means that if variable is zero length (or undef), use "foo" inste +ad. (variable:/blah/baz) (variable:|blah|baz) This means to expand variable, and, if successful, modify the value be +fore replacement using "s/blah/baz/g". Regular expressions are allowed. Two forms are + permitted in case one is using the special character you need. Note that the ) or +} characters are not permitted in here. =cut sub expand_string { my $self = shift; my $string = shift; my $func = shift || sub { $self->expand_variable(@_) }; local $_; my $varre = qr/ ([^:]*?) # variable name (?::(.*?))? # special instructions /x; my @s = split / (?: # either (\()$varre(\)) # parenthesis variable ) | # or... (?: (\{)$varre(\}) # brace variable )/x, $string; my $output; my $replace_sub; $replace_sub = sub { return '' if @_ == 0; return @_ if @_ == 1; my ($pre, $open, $var, $alternate, $close, @post) = @_[0, defined $_[1] ? (1..4) : (5..8), 9..$#_]; map { if ($alternate) { my ($cmd, $alt) = $alternate =~ /^(.)(.*)$/; if ($cmd eq '+') { if (defined and length) { $_ = $alt; } } elsif ($cmd eq '-') { unless (defined and length) { $_ = $alt; } } elsif ($cmd eq '/' or $cmd eq '|') { my ($re,$replace) = split /$cmd/, $alt; eval "s$cmd$re$cmd$replace$cmd"; die $@ if $@; } } if (not defined) { $_ = join '', $open, $var, $alternate ? (':',$alternat +e) : (), $close; } my $this = $pre . $_; map { $this . $_ } $replace_sub->(@post); } do { local $_ = $var; ($func->()) }; }; my %rc; { my $i = 0; $rc{$_} ||= ++$i foreach $replace_sub->(@s); } my @r = sort { $rc{$a} <=> $rc{$b} } keys %rc; if (wantarray) { @r; } elsif (scalar @r == 1) { $r[0]; } else { \@r; } } =item expand_variable Expands $_ to the values that it cares about. Returns an array of values for this variable. =cut sub expand_variable { my $self = shift; # just a dummy for now. qw(A B); # could be: # map { /^(.*)\.\.(.*)/ ? $1..$2 : $_ } split /,/ # or something like that, for example. }

Update: Code fixes - missed @_==0 case, allow scalar return if expansion does not give multiple return values. Remember - this code can do more than just turn a simple scalar into a list (although that's where the thread started). It can perform arbitrary replacements which may be one-to-one. The expand_variable routine can return a single string which causes the whole thing to return a single string.

Replies are listed 'Best First'.
Re^2: String expansion script
by blazar (Canon) on Feb 18, 2005 at 13:46 UTC
    I just want to thank you - being able to read this thread has saved me hours of work. Or cost me hours. Depends on how you look at it. I spent about 3 hours trying to get a similar version to work, and it finally does now. Hopefully this gives me such a simplified API to doing what I am trying to do that it will save me (and my cow-orkers) enough time to justify that... Even if it doesn't, it's a cool API to work with. :-)
    And I thank you in turn for your kind words. I gave a glance at your code and I noticed that it's not a snippet any more. Unfortunately I can't watch it in more detail: I wonder wether in the end you're matching the patterns balanced-wise as to allow for newsted ones...

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://432143]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (6)
As of 2024-04-16 05:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found