Skip to content

Instantly share code, notes, and snippets.

@leszekdubiel
Created February 9, 2019 20:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leszekdubiel/46aa24388b067bc31c2e758ace6f3f51 to your computer and use it in GitHub Desktop.
Save leszekdubiel/46aa24388b067bc31c2e758ace6f3f51 to your computer and use it in GitHub Desktop.
printf "\tname John\tage 24\t\ncity Kraków\tname Ann\tabout works here\tage 45\n\tspeaks Polish\tname Leszek\t\r\v\b\t\tnote malformed line still works\n" | perl -e 'use utf8; use Modern::Perl qw{2017}; use Data::Dumper; no warnings qw{uninitialized}; while (<STDIN>) { my %h = map { split / /, $_, 2 } grep { / / } split /[^[:print:]]/, $_, -1; 0 && warn Dumper(\%h); print "\t$_ $h{$_}" for @ARGV ? @ARGV : sort keys %h; print "\t\n"; }' name age about
@b2gills
Copy link

b2gills commented Feb 10, 2019

printf "\tname John\tage 24\t\ncity Kraków\tname Ann\tabout works here\tage 45\n\tspeaks Polish\tname Leszek\t\r\v\b\t\tnote malformed line still works\n"

This is the input to the one-liner:

	name John	age 24	
city Kraków	name Ann	about works here	age 45
	speaks Polish	name Leszek	
		note malformed line still works

First let's turn the Perl one-liner into something easier to understand

use utf8;
use Modern::Perl qw{2017};
use Data::Dumper;
no warnings qw{uninitialized};

while (<STDIN>) {
  my %h = map { split / /, $_, 2 } grep { / / } split /[^[:print:]]/, $_, -1;
  0 && warn Dumper(\%h);

  print "\t$_ $h{$_}"
    for
      @ARGV ? @ARGV : sort keys %h;

  print "\t\n";
}

The split /[^[:print:]]/, $_, -1 produces something like:

("", "name John", "age 24", "", "")
("city Kraków", "name Ann", "about works here", "age 45", "")
("", "speaks Polish", "name Leszek", "", "", "", "", "", "note malformed line still works", "")

The grep { / / } cleans it up to

("name John", "age 24")
("city Kraków", "name Ann", "about works here", "age 45")
("speaks Polish", "name Leszek", "note malformed line still works")

That combination directly translates to:

.split( /<:C>/ ) # split on control characters
.grep( ?* )      # skip empty

The thing is .split can take a :skip-empty named parameter:

.split( /<:C>/, :skip-empty )

But we can do better than that with .comb:

.comb( / <print>+ / ) # grab sequences of printable characters

Next up is map { split / /, $_, 2 }.
It takes the above strings and splits them at the first space.

».split(" ",2)

That creates a list of lists, so we need to add a .flat


This is what we have so far:

use v6.d;

for $*IN.lines() {
  my %h = .comb( / <print>+ / )».split(" ",2).flat
}

We have to add the part where it takes an argument or sorts by key, and prints it:

use v6.d;

for $*IN.lines() {
  my %h = .comb( / <print>+ / )».split(" ",2).flat;

  print "\t$_ %h{$_}" for @*ARGS || %h.keys.sort;
  
  print "\t\n";
}

That complains about undefined values in the print statement.

We don't care about that so we tell it to be quiet with quietly

use v6.d;

for $*IN.lines() {
  my %h = .comb( / <print>+ / )».split(" ",2).flat;

  quietly print "\t$_ %h{$_}" for @*ARGS || %h.keys.sort;
  
  print "\t\n";
}

Now to combine it into a one-liner, and remove other extra characters.

for $*IN.lines {my %h=.comb(/<print>+/)».split(" ",2).flat;quietly print "\t$_ %h{$_}" for @*ARGS||%h.keys.sort;print "\t\n"}
perl6 -e 'for $*IN.lines {my %h=.comb(/<print>+/)».split(" ",2).flat;quietly print "\t$_ %h{$_}" for @*ARGS||%h.keys.sort;print "\t\n"}'

@leszekdubiel
Copy link
Author

O! Thank you... I think I didn't get email that you have commented. I will test that too.
:)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment