Regex pattern question for rows not exactly equal

Viewed 44

I have a problem when downloading and extracting tables from a pdf. Currently, I am at the phase of extracting the "contents" table which I will use as index for the rest of the document. My problem is that there are three columns in the table formatted as one string, some have one space between the first and second column and some hace two or more. Which regex pattern should I use?

As an example:

a <- "15 Aguascalientes - Ent. Cd. de Los Niños                             AGS"
b <- "3   Aguascalientes - Zacatecas                                       MEX-045"
str_split_fixed(a, "\\s{2,}", n = 3)
str_split_fixed(b, "\\s{2,}", n = 3)

The output I want is like the one for "b"

enter image description here

2 Answers

You can use stringr::str_match to capture each part you need:

library(stringr)
x <- c( "15 Aguascalientes - Ent. Cd. de Los Niños                             AGS", "3   Aguascalientes - Zacatecas                                       MEX-045")
matches <- str_match(x, "^(\\d+)\\s+(.*?)\\s+(\\S+)$")[,-1]
matches
# =>      [,1] [,2]                                     [,3]     
# => [1,] "15" "Aguascalientes - Ent. Cd. de Los Niños" "AGS"    
# => [2,] "3"  "Aguascalientes - Zacatecas"             "MEX-045"

See the online R demo and the regex demo. Regex details:

  • ^ - string start
  • (\d+) - Group 1: one or more digits
  • \s+ - one or more whitespaces
  • (.*?) - Group 2: any zero or more chars other than line break chars, as few as possible
  • \s+ - one or more whitespaces
  • (\S+) - Group 3: one or more non-whitespace chars
  • $ - string end.

With str_split we could specify an OR (|) condition to split at one or more space (\\s+) after a digit in addition to the OP's regex of splitting at more than one space character.

library(stringr)
str_split(c(a, b), '(?<=\\d)\\s+|\\s{2,}')

-output

#[[1]]
[1] "15"                                     "Aguascalientes - Ent. Cd. de Los Niños" "AGS"                                   

#[[2]]
[1] "3"                          "Aguascalientes - Zacatecas" "MEX-045"    

Assuming the OP wanted a three column data.frame, we can replace those spaces with a common delimiter , and read with read.csv in base R (which make sure that the column types are correct)

read.csv(text = gsub("(?<=\\d)\\s+|\\s{2,}", ",", c(a, b), 
       perl = TRUE), header = FALSE)
#  V1                                     V2      V3
#1 15 Aguascalientes - Ent. Cd. de Los Niños     AGS
#2  3             Aguascalientes - Zacatecas MEX-045
Related