kobame
kobame

Reputation: 5856

Perl three dot operator ... examples

Can anybody show with some examples the exact difference between .. and ... operator?

From the perlop man page:

If you don't want it to test the right operand until the next evaluation, as in sed, just use three dots ("...") instead of two.

But what exactly this mean? I don't understand the perlop's example:

@lines = ("   - Foo",
          "01 - Bar",
          "1  - Baz",
          "   - Quux"
);
foreach (@lines) {
    if (/0/ .. /1/) {
        print "$_\n";
    }
}

with ... will print the Baz - but why? More precisely, why is Baz not printed with two dots and only with ...?

Upvotes: 31

Views: 5074

Answers (4)

Flimm
Flimm

Reputation: 150573

Article

There's a great article called Dots and Perl, I recommend you read it.

To summarise:

One Dot

  • Concatenation operator:

    say "one" . "two";
    # Outputs "onetwo"
    

Two dots

  • Range operator:

    my @numbers = (1..100); # has one hundred numbers from 1 to 100
    
  • Flip-flop operator:

    while (my $line = readline($fh)) {
        process_this_line($line) if m/START/ .. m/END/;
    }
    

Three dots

  • Yada-yada statement:

    sub example {
        ...
        # throws "Unimplemented" exception when called
    }
    
  • Flip-flop operator, three-dot version:

    while (my $line = readline($fh)) {
        process_this_line($line) if m/START/ ... m/END/;
        # The only difference between this and the two-dot version
        # occurs when a single line has both START and END
    }
    

The other answers go into more detail on the difference between the two flip-flop operators.

Upvotes: 3

ikegami
ikegami

Reputation: 385645

«...» doesn't do a flop check immediately after a true flip check.

With «..»,

  1. " - Foo"
    1. /0/ returns false.
    2. .. returns false.
  2. "01 - Bar"
    1. /0/ returns true. Flip!
    2. /1/ returns true. Flop!
    3. .. returns true (since the first check was true).
  3. "1 - Baz"
    1. /0/ returns false.
    2. .. returns false.
  4. " - Quux"
    1. /0/ returns false.
    2. .. returns false.

With «...»,

  1. " - Foo"
    1. /0/ returns false.
    2. ... returns false.
  2. "01 - Bar"
    1. /0/ returns true. Flip!
    2. ... returns true.
  3. "1 - Baz"
    1. /1/ returns true. Flop!
    2. ... returns true.
  4. " - Quux"
    1. /0/ returns false.
    2. ... returns false.

Upvotes: 18

theglauber
theglauber

Reputation: 29595

Repeating the example here:

@lines = ("   - Foo",
          "01 - Bar",
          "1  - Baz",
          "   - Quux"
);
foreach (@lines) {
    if (/0/ .. /1/) {
        print "$_\n";
    }
}

It's tricky... what's happening when you use the 2 dots .. is that when you reach "01 - Bar", both conditions are tested and both succeed (because that line has a 0 and also a 1). So your printing is turned on and immediately turned off.

However, when you use ..., the first condition succeeds, but the second one is not tried until the next iteration of the loop, so "01 - Bar" turns it on and "1 - Baz" turns it off. Thus you see both lines printed.

The tricky part is to realize that the "01 - Bar" satisfies both tests.

Upvotes: 4

kjp
kjp

Reputation: 3116

If you have cases like /start/ .. /end/ with input

start some text end
start
some other text
end

the .. operator will process the end in the first line as soon as it reads it and will only print some text. The ... operator will not process the end on the first line so the other text will also be printed. Basically you can avoid stopping the range if the ending value is matched on the same line as the start. The ... postpones the check until the next iteration.

Upvotes: 4

Related Questions