-1

I am trying to extract several data fields out of somewhat peculiarly formatted strings.

Each string has a format similar to the following (spaces added for emphasis):

1 abcd 2 1 efg 2 hij 3 klmnopqrs 5 tuv 6 5 wxyzäüö 6

where each number represents another field delimiter. This is what I am trying to extract:

  abcd           hij   klmnopqrs 5 tuv 6   wxyz 

The 1..2 and 5..6 patterns occur only once in some cases. 1..2 ranges only appear before 3. 5..6 ranges only appear after 3.

So far I have been successful in extracting abcd and hij with the following code:

  • abcd:

    echo "$STRING" | awk 'BEGIN{ RS="2"}{gsub(/.*1/,"");print;exit}'
    
  • hij:

    echo "$STRING" | awk 'BEGIN{ RS="3"}{gsub(/.*2/,"");print;exit}'
    

Now I am looking for a way to grab wxyz and klmnopqrs.

  • wxyz are the first four characters in the last 5..6 range pattern of the string
  • klmnopqrs is the field delimited by the first occurrence of 3 and the last occurrence of 5

After searching the web for an hour I am now at wit's end. I'd appreciate any help in finding a way to extract these range patterns.

Edit: Here's a few input samples that are closer to the real deal:

(test)(te st) tesst. test test test test [teest] [teseeet]
(teeeest)(te st) tst. tet test [teseet]
(tst) tst. tet test [tseeet]

This is what I would like to extract in each case:

 test         tesst  test test test test [teest] tese
 teeeest         tst  tet test tese
 tst  tst  tet test  tsee

The field delimiters are special characters, as you an see. Both the width of the strings and the number of 1..2 and 5..6 ranges (here (..) and [..]) are variable.

  • 1
    how about an actual sample of the input? Are the delimiters actually numbers, or some other characters? Are these fixed-width lines? – user61786 Apr 21 '14 at 11:51
  • @awk_FTW Thanks for the pointers. I updated my question with more information. – Glutanimate Apr 21 '14 at 15:12
2
echo "1 abcd 2 1 efg 2 hij 3 klmnopqrs 5 tuv 6 5 wxyzäüö 6" | 
perl -lne '
    @out = ();
    /1 (.+?) 2/                 and push @out, $1;
    /.+2 \K(.+?) 3 (.+?)(?= 5)/ and push @out, $1, $2;
    /(5.+?6)/                   and push @out, $1;
    /.+5 (....)/                and push @out, $1;
    print join " ", @out
'
abcd hij klmnopqrs 5 tuv 6 wxyz

We need to take care to escape the regex special chars properly:

perl -lne '
    @out = ();
    /\((.+?)\)/                 and push @out, $1;
    /.+\) \K(.+?)\.(.+)(?= \[)/ and push @out, $1, $2;
    /.+\[(....)/                and push @out, $1;
    print join " ", @out
' <<END
(test)(te st) tesst. test test test test [teest] [teseeet]
(teeeest)(te st) tst. tet test [teseet]
(tst) tst. tet test [tseeet]
END
test tesst  test test test test [teest] tese
teeeest tst  tet test tese
tst tst  tet test tsee

Your desired output:

 test         tesst  test test test test [teest] tese
 teeeest         tst  tet test tese
 tst  tst  tet test  tsee
  • Thank you very much. Your answer works perfectly for the example I provided. Unfortunately I think that I abstracted my example a bit too much. The real input is delimited by special characters. When I replace the numbers in your script with the (escaped) delimiters it outputs the wrong fields. Is there any chance you could take another look at my edited question? – Glutanimate Apr 21 '14 at 15:11
  • 1
    @Glutanimate that's why you should provide an actual sample of the input. If it contains sensitive information, just change the information not the format and such. A line of test test test is not very helpful either though. – user61786 Apr 22 '14 at 4:29
  • @ Glenn: Thank you. This is absolutely brilliant! @awk_FTW: You're right and I'll make sure to do it like that from now on. – Glutanimate Apr 22 '14 at 5:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.