-1

EDIT: I'm not just trying to solicit people writing this code for me.....I have been trying at this for about a day, and despite having a perl textbook, I still can't figure it out. Like I said, I CAN do it using grep/awk/sed, and also by piping together multiple perl one-liners....I just can't figure out how to do it in one perl invocation.

I'm new to Perl so this one will be quick and easy to answer.

I'm trying to write a script that will parse a file line-by-line and print the first word on a line that is contained between quotes, but only on lines that contain a specific string at the EOL (string is passed as an argument). The file in a C header file that, along with lots of other junk in it, contains a struct definition in the format below, which has the strings I want to extract.

struct Foo_t foo
{

    /* str_HELLO */
    { {5,4,8,7,9},
      {     "HELLO!",      // English 
            "BONJOUR!",    // French
            "Hallo!",       // German 
            "BONJOURNO!",   // Italian
            "HOLA!"         // Spanish
    } }, 

    /* str_GOODBYE */
    { {15,3,3,3,3},
      {     "GOODBYE!",     // English 
            "AU REVOUIR!",   // French
            "TSCHUSS!",      // German 
            "CIAO!",         // Italian
            "ADIOS!"      // Spanish
    } }, 


    /* str_FOO */
    { {15,3,3,3,3},
      {     "FOO",      // English 
            "BAR",      // French
            "NOO",      // German 
            "BAZ",      // Italian
            "OOF"       // Spanish
    } },


    // lots more of these....
    // .... 

And to get the desired output, I would want the invocation to be

bash~$: myscript.pl -language=english file_to_be_parsed.h 

I can easily do this by piping together greps, but I really wanna get this in perl. I've tried to do this simple task via a script and also with a one-liner, but none of have worked. Since this is so quick, if any perl wizards could show me the light, along with an explanation for the matching stuff, it would be much appreciated.

Thanks in advance!!

asmvolatile
  • 522
  • 5
  • 22
  • 1
    This reads like "please write this program for me" combined with "I don't know how to do it, so it must be easy". – melpomene Jul 25 '15 at 22:05
  • I have been trying at this for about a day, and despite having a perl textbook, I still can't figure it out. Like I said, I CAN do it using grep/awk/sed, and also by piping together multiple perl one-liners. So its not "write this program for me so I can accomplish my task", its more of "I want to learn the elegant way to do this" – asmvolatile Jul 25 '15 at 22:12
  • So ask a concrete question about something you're stuck on. – melpomene Jul 25 '15 at 22:13
  • "I'm not just trying to solicit people writing this code for me" - then what kind of answer are you looking for? – melpomene Jul 25 '15 at 22:25
  • @melomene Ok, here's a specific question...how can I condense the following TWO perl CLI invocations into one (ie do the same thing, but without piping)? `perl -wnle '/english/i and ($_ =~ /\"(\w)*\"/ and print $&);' sp2_string.h | perl -wlne 's/[",]//g and print;'` – asmvolatile Jul 25 '15 at 22:32
  • Change `(\w)*` to `(\w*)` and `$&` to `$1`. – melpomene Jul 25 '15 at 22:34
  • @melomene Thanks! Could you explain the significance of those changes for me please? Because doesn't (\w)* greedy-match 0 or more word characters up until the end quotes? – asmvolatile Jul 25 '15 at 22:37
  • If you've been working for so long on this you should have some code that you can show and explain the problem you are having with it – Borodin Jul 25 '15 at 23:26

3 Answers3

1

An experimental feature of v5.22 is code evaluation expressions. You can execute code from within the regex if it succeeds. That, combined with a positive lookahead, you get this:

/"(.*?)".*(?=english)(?{print "$1\n";})$/i;
Håkon Hægland
  • 39,012
  • 21
  • 81
  • 174
stevieb
  • 9,065
  • 3
  • 26
  • 36
0

answer from @melomene in the comments did the trick.

I went from

perl -wnle '/english/i and ($_ =~ /\"(\w)*\"/ and print $&);' file.h | perl -wlne 's/[",]//g and print;' 

to

perl -wnle '/english/i and ($_ =~ /\"(\w*)\"/ and print $1);` file.h
asmvolatile
  • 522
  • 5
  • 22
  • `$_ =~` is redundant because `$_` is the default target of the match operator (you already make use of this in `/english/i`). `"` aren't special in regexes and don't need to be escaped. – melpomene Jul 25 '15 at 22:46
  • This won't work with your sample data as `\w` doesn't match exclamation marks `!` – Borodin Jul 25 '15 at 23:24
0

Something like this is an improvement on your own solution. It should be called as

perl filter_header.pl english header.h
use strict;
use warnings;

open my $fh, '<', $file or die qq{Unable to open "$file" for input: $!};

while ( <$fh> ) {
  next unless m| // \s* \Q$lang |ix;
  print $1, "\n" if / " ([^"]*) " /x;
}

output

HELLO!
GOODBYE!
FOO
Borodin
  • 126,100
  • 9
  • 70
  • 144