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.


In reply to Re: String expansion script by Tanktalus
in thread String expansion script by blazar

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.