Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Looking for a somewhat clever way to do this.

I have an input file which consists of fixed length (10 characters) lines containing a-z.

For each line, I want to build and print a regexp string that I will use elsewhere.

The regexp string will begin (before processing each line):

'/bin/grep .......... /path/to/some/file'

For each 'x' character in the input file, I want to replace the corresponding dot in the regexp with say the corresponding digit of pi (1415926535).

For example, if a line in input file contains an 'x' in the third character (but not the first and second), the regexp string should become:

'/bin/grep ..1....... /path/to/some/file'

If the next 'x' occurs in the seventh character of the line, then the string should become:

'/bin/grep ..1...6... /path/to/some/file'

I feel like some simple way should exist to do this, but my attempts have just become a mess of code.

Replies are listed 'Best First'.
Re: string substitution
by choroba (Cardinal) on Feb 23, 2022 at 11:20 UTC
    #!/usr/bin/perl use warnings; use strict; my @pi = split //, '1415926535'; while (<DATA>) { 1 while s/ ([^ ]*?)\Kx/$pi[length $1]/; print; } __DATA__ /bin/grep .......... /path/to/some/file /bin/grep xxxxxxxxxx /path/to/some/file /bin/grep x....x...x /path/to/some/file

    For each x, find the string between it and its preceding space. Its length is the position in the "mask".

    Update: If the path can contain x, you need more caution, e.g. s/^[^ ]+ ([^ ]*?)\Kx/$pi[length $1]/g.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: string substitution
by LanX (Saint) on Feb 23, 2022 at 11:38 UTC
    use v5.12; use warnings; # https://perlmonks.org/?node_id=11141581 my $in = "anXwxdXdzd"; my $pi = "1415926535"; my @in = split //, $in; my @pi = split //, $pi; my $re = join "", map {$in[$_] eq "X" ? $pi[$_] : '.' } 0..9; $re = "/bin/grep $re /path/to/some/file"; say $re;
    OUTPUT:
    /bin/grep ..1...6... /path/to/some/file

    edit

    FWIW: Perl can apply mask operations with & , ^ and | , but this would also first require translating X to chr(255) and else to chr(0). see tr and s for that approach.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

    updates

    • code now closer to OP's input data
      > FWIW: Perl can apply mask operations with & , ^ and | , but this would also first require translating X to chr(255) and else to chr(0). see tr and s for that approach.

      (used uppercase X for demo only, switching to lowercase works too)

      use v5.12; use warnings; # https://perlmonks.org/?node_id=11141581 my $in = "anXwxdXdzd"; my $pi = "1415926535"; my $mask = $in =~ tr/Xa-z/\xff\x00/r; my $re = $pi & $mask; $re=~ tr/\x00/./; $re = "/bin/grep $re /path/to/some/file"; say $re;
      OUTPUT:
      /bin/grep ..1...6... /path/to/some/file

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

      That worked perfectly. Thank you. I have a twist to add, though. After creating the initial regexp, I want to now check for the letter 'q' in the input string. For each 'q' found, I want to append (for example, with a 'q' in the fourth character of the input line) to the regexp:

      ' | grep -v ...5......'
      So now, instead of a positive match, I want to check for a negative match (and if I understand regexes, I would need to add that string for each 'q' found in the input line).
        You should at least provide valid data in the sense of an SSCCE, your description is cryptic.

        Anyway, ISTM you want a character class [^5] in the regex to match anything but 5.

        Please expand the code provided to your needs, and show us what you tried.

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery