6

Given the input file:

----------------
A
----------------
information for A
on these lines
----------------
B
----------------
Something about B
on these lines
etc

I want to produce:

A: information for A
A: on these lines
B: Something about B
B: on these lines
B: etc

My attempt to use Raku to do this looks like:

#!/usr/bin/env raku

my $head-info;

for lines() -> $line {
    given $line {
#        when /^ '-' **16 $/ { }   # skip dashed lines
        when /^ '-' **16 $/ ^fff^ /^ '-' ** 16 $ / {
           $head-info = $line;
           say "set head-info $head-info";
        }
        default { say $head-info, ": ", $line; }
    }
}

I tried some variations of this but never seem to be able to execute the block that sets $head-info. Uncommenting the line does skip the dashed lines. I don't necessarily need to use ff or fff but I thought it would be appropriate here.

2 Answers 2

3

I tried some variations of this but never seem to be able to execute the block that sets $head-info

I think both when and the ff family doing $_ ~~ operations is resulting in the undesired output by messing up with $_ somehow. So to bypass this, we can either do when so ... or use plain if. I choose the latter to get:

my $head-info;

for lines() -> $line {
    $_ := $line;

    if /^ "-"+ $/ ^fff^ /^ "-"+ $/ {
        $head-info = $line;
    }
    elsif !/^ "-"+ $/ {
        say "$head-info: $line";
    }
}

where I now manually bind $_ to the line at hand for ^fff^. So the code now says

  • if we are between all-"-" lines, save this line as the header information
  • otherwise, if we are not at an all-"-" line, we have the information body, so say it with the current header

Note that all-"-" lines satisfy neither of these, so they are silently skipped in the loop.


Extra: the part

for lines() -> $line {
    $_ := $line;

is slightly annoying to do manually, there's a third-party library that introduces the forgiven keyword that combines the for loop and a given statement and does that binding on $_ behind the scenes, so one can do:

use Slang::Forgiven;

my $head-info;

forgiven lines() -> $line {
    if /^ "-"+ $/ ^fff^ /^ "-"+ $/ {
        $head-info = $line;
    }
    elsif !/^ "-"+ $/ {
        say "$head-info: $line";
    }
}

to get the same result.

Disclaimer: author.

Sign up to request clarification or add additional context in comments.

Comments

1

Using (one-or-more) Raku one-liners:

~$ raku -e 'my %h; for lines.skip.kv.rotor(2) { 
                   %h.push: $_ if /^ "-" **16 $/ ^fff^ /^ "-" **16 $/ 
            };  .say for %h.sort: +*.key;'   file  >>  newfile

The Raku code above will skip the first line of the file, then collect the "information for A" lines as requested. These will appear with their authentic line-numbers as keys.

Sample Input:

----------------
A
----------------
information for A
on these lines
----------------
B
----------------
Something about B
on these lines
etc
----------------

Sample Output:

2 => information for A
3 => on these lines
7 => Something about B
8 => on these lines
9 => etc

By running multiple one-liners (with/without the call to skip), you can >> append output into the same newfile, collecting the information required to reconstruct the output as you desire.

HTH.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.