开发者

Perl String formatting

Here is a string

[ Move ] [ Source ] [ Destination ]

Now I want to move "move", "source", "destination" into variables.

This is my code

  #Try grab the "move" part.
  $data = "[ Move ] [ Source ] [ Destination ]"
  $start = index($data, '[') + 2;
  $end   = index($data, ']') - 2; #The +- 2 is to get rid of the spaces
  $cmd = substr $data, $start, $end; #This does not work. No idea why.
  $data = substr $data,  $end;
  $start = index($data, '[') + 2;
  $end   = index($data, ']') - 2;
  $source = substr $data, $start, $end;
  $data = substr $data,  $end;
  $start = index($data, '[') + 2;
  $end   = index($data, ']') - 2;
  $destination = substr $data, $start, $end;

Thanks in adv开发者_JS百科ance.


Maybe something like this:

my $input = '[ Move ] [ Source ] [ Destination ]';
my ($mov, $src, $dst) = $input =~ /\[ \s* (.*?) \s* \]/gx;
print "$mov $src $dst\n";


Many ways to do this in Perl. One is to use regular expressions:

if ($data =~ /^\[([^\]]+)\]\s*\[([^\]]+)\]\s*\[([^\]]+)\]/) {
    my $command = $1;
    my $source = $2;
    my $destination = $3;
}
else {
    die "Didn't match\n";
}

It's a bit ugly. Basically \[ and \] matches your square brackets. You have to prefix them with a backslash because brackets are magical in regular expressions. The [^\]] matches non-closing brackets. The [^x] means anything but x. The plus sign on the end means at least one. Thus [^\]]+ matches as many characters as it can until it comes to another closing bracket. The curved parentheses around the expression saves it in the $1, $2, and $3 variables. I repeat this for each item I'm matching.

There's a way of looping through a regular expression to keep finding matching parts, but that's a little more complicated than you want to get into right now.

Another is to use the split command:

$data =~ s/^\[(.*)\]$/$1/;
my ($move, $source, $destination) = split (/\]\s*\[/, $data);

The first line removes the prefixing and appending brackets, and then I split on the "] [" brackets. Again, I'm using regular expressions.

Regular expressions are the life blood of Perl, and you should learn about them as much as you can. Perl takes the standard Unix regular expressions, and expands them quite a bit. You can type in perldoc perlre to find documentation about regular expressions and how they're used, but it's more of a reference manual and not a tutorial. You can also try perldoc perlrequick which is more of a tutorial.


There are a number of ways that you could do this.

  1. Split the string on ] [ and remove the extra brackets from the fields, eg.

    my @strings = 
        map { s/^[|]$//; $_ } 
        split '] [', $input;
    
  2. Or use a regex to extract each bit of the string enclosed by square brackets.

    my @strings = ( $input =~ m{\[\s*(.*?)\s*\]}g );
    

However, these approaches can fall down if you have nested square brackets.


First off, is there a reason why you're doing it this way instead of using a regex to capture the interesting data?

my ($cmd, $source, $destination) = $data =~ /^\[ ([^]]*) \]\[ ([^]]*) \]\[ ([^]]*) \]$/`

As for why the code you posted doesn't work, the line you say doesn't work actually works just fine - $cmd is getting the text "Move" just as it should. But, after you remove the "Move" from $data, take a look at what you have left: "e ] [ Source ] [ Destination ]" The next time you set $start, that works fine, but setting $end finds the first ] in the string, so $source gets the substr from position 6 to position 0; since the range ends before it starts, that's an empty string. Setting $destination has the same problem, so that also comes up empty.

When trying to debug a problem, always check your variables to verify that they're holding the values that you think they are. As in this case, they usually aren't.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜