Regular expression to extract fields with different whitespace

Viewed 69

I'm processing some PDFs (each with a big table inside) with pdftotext and my output is a plain text file with different lines. From the file, which I would like to read line by line, I want to extract only those lines with the following formatting and ignoring the rest:

YYYYYYYY A ZZZ BBBBBB BBB BBBBBB ZZZZZZZ C ZZZ DDDDDD DDD DD ZZZZZ E ZZZ FFFFFF FFF FFF ZZZZZ G (ZZZZ HHHH HHH HHHHH)
         ^     ^                         ^     ^                   ^     ^                    ^       ^

Y = whitespace or text => IGNORED
A = 1 digit => CAPTURED
B = text with spaces => CAPTURED
C = 1 digit => CAPTURED
D = text with spaces => CAPTURED
E = 1 digit => CAPTURED
F = text with spaces => CAPTURED
G = 1 digit => CAPTURED
H = text with spaces => CAPTURED, if present
Z = whitespace (variable length >= 3 chars) => IGNORED
() = this part may or may not be present

I tried with the following regex:

^.+(\d)\s+(.{3,}?)\s{3,}(\d)\s+(.{3,}?)\s{3,}(\d)\s+(.{3,}?)\s{3,}(\d)\s+(.{3,}|)$

It works but RegexBuddy says that it leads to a "catastrophic backtracking". So what would be the correct way to handle it? I need to capture the groups A..H to do my processing.

EDIT: Adding a couple of testing lines with fictional words:

                                                                                                                                                                                                      01/11/2020                          03/11/2020

           N.                      First header                                      N.                       Secondo header                              N.                         Third head   N.                    Last optional header

           1   COURAGE AND STOCKS EVERYTHING TO                                      1       SHE SAYS SHE HAS THE ABILITY                                 1   CHILD BY THE TO                     1   JITTERY X) CLASSIC - A6

           2   SHE LIKES ALL THE SAME THINGS                                         2       CROWD YELLS AND SCREMS MORE THEN MEMESU                      2   WEDGES PROBABLY ARE NOT             2   FRAGILE Y) BOILINGE - A6
           3   SOUNDTRACK OF ME                                                      3       DROPPING ALL THE MONTHS                                      3   THE BEST FOR RELATIONSHIPS AT       3   NATURAL Z) ENVIOUSLYER - A6
Nothere    4   GOING AND HE COULD HEAR THUNDER IN KUNE                               4       WONDERED IF HER LIE                                          4   CHANGED FOREV LT.200/250            4
           5   MUSTER N.2 GROUNDKEE OF MY. 230                                       5       LEMONADE SHOWERS OF                                          5   FOCUS JUST MOST                     5

Expected results, line by line:

  1. Fail (there are two dates)
  2. Fail (empty line)
  3. Fail (doesn't have numbers, format mismatch)
  4. Fail (empty line)
  5. Match
  6. Fail (empty line)
  7. Match
  8. Match
  9. Match (the "Nothere" text should be ignored of course)
  10. Match
1 Answers

Use

^.*?\s(\d)\s+(\S.*?)\s+(\d)\s+(\S.*?)\s+(\d)\s+(\S.*?)\s+(\d)(?:\s+(\S.*))?$

See proof.

Explanation

--------------------------------------------------------------------------------
  ^                        the beginning of the string
--------------------------------------------------------------------------------
  .*?                      any character except \n (0 or more times
                           (matching the least amount possible))
--------------------------------------------------------------------------------
  \s                       whitespace (\n, \r, \t, \f, and " ")
--------------------------------------------------------------------------------
  (                        group and capture to \1:
--------------------------------------------------------------------------------
    \d                       digits (0-9)
--------------------------------------------------------------------------------
  )                        end of \1
--------------------------------------------------------------------------------
  \s+                      whitespace (\n, \r, \t, \f, and " ") (1 or
                           more times (matching the most amount
                           possible))
--------------------------------------------------------------------------------
  (                        group and capture to \2:
--------------------------------------------------------------------------------
    \S                       non-whitespace (all but \n, \r, \t, \f,
                             and " ")
--------------------------------------------------------------------------------
    .*?                      any character except \n (0 or more times
                             (matching the least amount possible))
--------------------------------------------------------------------------------
  )                        end of \2
--------------------------------------------------------------------------------
  \s+                      whitespace (\n, \r, \t, \f, and " ") (1 or
                           more times (matching the most amount
                           possible))
--------------------------------------------------------------------------------
  (                        group and capture to \3:
--------------------------------------------------------------------------------
    \d                       digits (0-9)
--------------------------------------------------------------------------------
  )                        end of \3
--------------------------------------------------------------------------------
  \s+                      whitespace (\n, \r, \t, \f, and " ") (1 or
                           more times (matching the most amount
                           possible))
--------------------------------------------------------------------------------
  (                        group and capture to \4:
--------------------------------------------------------------------------------
    \S                       non-whitespace (all but \n, \r, \t, \f,
                             and " ")
--------------------------------------------------------------------------------
    .*?                      any character except \n (0 or more times
                             (matching the least amount possible))
--------------------------------------------------------------------------------
  )                        end of \4
--------------------------------------------------------------------------------
  \s+                      whitespace (\n, \r, \t, \f, and " ") (1 or
                           more times (matching the most amount
                           possible))
--------------------------------------------------------------------------------
  (                        group and capture to \5:
--------------------------------------------------------------------------------
    \d                       digits (0-9)
--------------------------------------------------------------------------------
  )                        end of \5
--------------------------------------------------------------------------------
  \s+                      whitespace (\n, \r, \t, \f, and " ") (1 or
                           more times (matching the most amount
                           possible))
--------------------------------------------------------------------------------
  (                        group and capture to \6:
--------------------------------------------------------------------------------
    \S                       non-whitespace (all but \n, \r, \t, \f,
                             and " ")
--------------------------------------------------------------------------------
    .*?                      any character except \n (0 or more times
                             (matching the least amount possible))
--------------------------------------------------------------------------------
  )                        end of \6
--------------------------------------------------------------------------------
  \s+                      whitespace (\n, \r, \t, \f, and " ") (1 or
                           more times (matching the most amount
                           possible))
--------------------------------------------------------------------------------
  (                        group and capture to \7:
--------------------------------------------------------------------------------
    \d                       digits (0-9)
--------------------------------------------------------------------------------
  )                        end of \7
--------------------------------------------------------------------------------
  (?:                      group, but do not capture (optional
                           (matching the most amount possible)):
--------------------------------------------------------------------------------
    \s+                      whitespace (\n, \r, \t, \f, and " ") (1
                             or more times (matching the most amount
                             possible))
--------------------------------------------------------------------------------
    (                        group and capture to \8:
--------------------------------------------------------------------------------
      \S                       non-whitespace (all but \n, \r, \t,
                               \f, and " ")
--------------------------------------------------------------------------------
      .*                       any character except \n (0 or more
                               times (matching the most amount
                               possible))
--------------------------------------------------------------------------------
    )                        end of \8
--------------------------------------------------------------------------------
  )?                       end of grouping
--------------------------------------------------------------------------------
  $                        before an optional \n, and the end of the
                           string
Related