regex.qmd

À la découverte des expressions régulières avec R (et d’autres packages au passage…)

Les expressions régulières sont communément appelées regex ou regexp pour regular expressions en anglais. Selon Wikipédia, une expression régulière est “une chaîne de caractères, qui décrit, selon une syntaxe précise, un ensemble de chaînes de caractères possibles”. Si vous n’avez jamais entendu parlé des regex, il se peut que cette définition ne vous aide pas à comprendre le concept. Nous tenterons de démystifier le tout au cours de ces exercices.

À titre de rappel, cet aide-mémoire vous sera drôlement utile!

En résumé, ces expressions permettent de décrire des motifs (patterns) à l’aide de formules “relativement simples” pour trouver, valider, extraire ou modifier du texte ou des nombres.

Mission d’aujourd’hui:

Récolter le plus d’information possible qui se trouve dans les tableaux de la page suivante: https://tc.canada.ca/fr/aviation/exploitation-aeroports-aerodromes/liste-aeroports-appartenant-transports-canada.

library(tidyverse)
── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
✔ ggplot2 3.3.6      ✔ purrr   0.3.4 
✔ tibble  3.1.8      ✔ dplyr   1.0.10
✔ tidyr   1.2.0      ✔ stringr 1.4.0 
✔ readr   2.1.3      ✔ forcats 0.5.2 
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
library(magrittr)

Attaching package: 'magrittr'

The following object is masked from 'package:purrr':

    set_names

The following object is masked from 'package:tidyr':

    extract
library(rvest)

Attaching package: 'rvest'

The following object is masked from 'package:readr':

    guess_encoding
URL <- "https://tc.canada.ca/fr/aviation/exploitation-aeroports-aerodromes/liste-aeroports-appartenant-transports-canada"

Début de solution en base R

base_raw_html <- read_html(x = URL)
base_html_table <- html_elements(x = base_raw_html, css = "table")
base_tables <- html_table(x = base_html_table)

# base_table <- rbind(base_tables[[1]], base_tables[[2]], base_tables[[3]])


names(base_tables[[3]])
[1] "Territoire"   "Aéroport"     "Exploité par"

⚠️ Erreur! Une colonne n’est pas nommée de façon identique, donc ne fonctionne pas… Corrigeons la situation

names(base_tables[[3]])[1] <- "Province/Territoire"

base_table <- rbind(base_tables[[1]], base_tables[[2]], base_tables[[3]])

base_table
# A tibble: 44 × 3
   `Province/Territoire`  Aéroport                `Exploité par`                
   <chr>                  <chr>                   <chr>                         
 1 "Colombie-Britannique" Penticton               "Transports Canada\n\t\t\t#10…
 2 ""                     Port Hardy              "Transports Canada\n\t\t\tC.P…
 3 ""                     Sandspit                "Transports Canada\n\t\t\tC.P…
 4 ""                     Havre de Victoria       "Transports Canada\n\t\t\t12,…
 5 "Manitoba"             Churchill               "Transports Canada\n\t\t\tC.P…
 6 "Québec"               Chevery                 "Municipalité de la Côte-Nord…
 7 ""                     Lourdes-de-Blanc-Sablon "Transports Canada\n\t\t\tAir…
 8 ""                     Sept-Îles               "Transports Canada\n\t\t\t100…
 9 ""                     Natashquan              "Municipalité de Natashquan\n…
10 ""                     Eastmain River          "Transports Canada\n\t\t\ta/s…
# … with 34 more rows
# Solution en Base R
base_table$`Province/Territoire` <- ifelse(test = is.na(base_table$`Province/Territoire`),
                                  yes = base_table$Territoire, no = base_table$`Province/Territoire`)
base_table$Territoire <- NULL

rm(list=(ls(pattern = "base*")))

Solution à la Tidyverse

URL <- "https://tc.canada.ca/fr/aviation/exploitation-aeroports-aerodromes/liste-aeroports-appartenant-transports-canada"


tables <- read_html(x = URL) %>%
    html_elements(css = "table") %>%
    html_table()

table <- dplyr::bind_rows(tables[[1]],
                          tables[[2]],
                          tables[[3]],
                          .id = "type")

# ou solution alternative équivalente
tables %>% purrr::map_dfr(bind_rows, .id = "type")
# A tibble: 44 × 5
   type  `Province/Territoire`  Aéroport                `Exploité par`   Terri…¹
   <chr> <chr>                  <chr>                   <chr>            <chr>  
 1 1     "Colombie-Britannique" Penticton               "Transports Can… <NA>   
 2 1     ""                     Port Hardy              "Transports Can… <NA>   
 3 1     ""                     Sandspit                "Transports Can… <NA>   
 4 1     ""                     Havre de Victoria       "Transports Can… <NA>   
 5 1     "Manitoba"             Churchill               "Transports Can… <NA>   
 6 1     "Québec"               Chevery                 "Municipalité d… <NA>   
 7 1     ""                     Lourdes-de-Blanc-Sablon "Transports Can… <NA>   
 8 1     ""                     Sept-Îles               "Transports Can… <NA>   
 9 1     ""                     Natashquan              "Municipalité d… <NA>   
10 1     ""                     Eastmain River          "Transports Can… <NA>   
# … with 34 more rows, and abbreviated variable name ¹​Territoire

Remplir les rangées de la colonne Province/Territoire

table <- table %>% dplyr::rename(province_territoire = `Province/Territoire`,
                        aeroport = Aéroport,
                        exploited_by = `Exploité par`,
                        territoire = Territoire)

table$province_territoire <- dplyr::coalesce(table$province_territoire, 
                                              table$territoire)



table[table == ""] <- NA
# equivalent en tidyverse
table$province_territoire <- table$province_territoire %>% dplyr::na_if(y = "")
table <- table %>% tidyr::fill(province_territoire, .direction = "down")
table <- table %>% dplyr::select(-territoire)

Extraction des codes d’aéroports

# solution #1
x <- table %>% mutate(new_col = str_extract(string = aeroport, pattern = "[A-Z]{3}"))

table <- table %>% tidyr::extract(col = aeroport,
                         into = "code_aeroport",
                         regex = "(Y[A-Z][A-Z])", 
                         remove = FALSE)

table$aeroport <- table$aeroport %>%
    stringr::str_remove_all(pattern = "\\(.*\\)") %>%
    stringr::str_squish()

Recodage des types d’aéroport

x <- table %>% mutate(type_nouveau = recode(type,
                                            "1" = "Petits aéroports",
                                            "2" = "Aéroports nationaux", 
                                            "3" = "Aéroports nationaux exploités par des administrations territoriales"))

x <- x %>% mutate(type_nouveau_case = case_when(type == 1 ~ "Petits aéroports", 
                                               type == 2 ~ "Aéroports nationaux",
                                               type == 3 ~ "Aéroports nationaux exploités par des administrations territoriales"))

Il ne reste plus qu’à extraire l’information qui se trouve dans table$exploited_by

table$exploited_by
 [1] "Transports Canada\n\t\t\t#109-3000 Airport Road\n\t\t\tPenticton (Colombie-Britannique)  V2A 8X1\n\t\t\t250-770-4414"         
 [2] "Transports Canada\n\t\t\tC.P. 460\n\t\t\t3675 Byng Road\n\t\t\tPort Hardy (Colombie-Britannique)  V0N 2P0\n\t\t\t250-949-6424"
 [3] "Transports Canada\n\t\t\tC.P. 439\n\t\t\tSandspit (Colombie-Britannique)  V0T 1T0\n\t\t\t250-637-1149"                        
 [4] "Transports Canada\n\t\t\t12, rue Erie\n\t\t\tVictoria (Colombie-Britannique)  V8V 1Y4\n\t\t\t250-363-3578"                    
 [5] "Transports Canada\n\t\t\tC.P. 1059\n\t\t\tChurchill (Manitoba)  R0B 0E0\n\t\t\t204-675-8868"                                  
 [6] "Municipalité de la Côte-Nord-du Golfe-du Saint-Laurent\n\t\t\tChevery (Québec)  G0G 1G0\n\t\t\t418-787-2215"                  
 [7] "Transports Canada\n\t\t\tAirport Road\n\t\t\tLourdes-de-Blanc-Sablon (Québec)  G0G 1W0\n\t\t\t418-461-2514"                   
 [8] "Transports Canada\n\t\t\t1000, boul. Laure Est\n\t\t\tC.P. 2001\n\t\t\tSept-Îles (Québec)  G4R 4K2\n\t\t\t418-962-8211"       
 [9] "Municipalité de Natashquan\n\t\t\tAirport Road\n\t\t\tNatashquan (Québec)  G0G 2E0\n\t\t\t418-726-3273"                       
[10] "Transports Canada\n\t\t\ta/s du conseil de bande\n\t\t\tEastmain (Québec)  J0M 1W0\n\t\t\t819-977-0333"                       
[11] "Transports Canada\n\t\t\t1550 B, route de l'Aéroport\n\t\t\tHavre-Saint-Pierre (Québec)\n\t\t\tG0G 1P0\n\t\t\t418-538-0627"   
[12] "Transports Canada\n\t\t\t1-210, chemin de l’Aéroport\n\t\t\tHavre-aux-Maisons (Québec)\n\t\t\tG4T 5L2\n\t\t\t418-969-2180"    
[13] "Transports Canada\n\t\t\ta/s du conseil de bande\n\t\t\tWaskaganish (Québec)  J0M 1R0\n\t\t\t819-895-8925"                    
[14] "Administration régionale Kativik\n\t\t\tC.P. 9\n\t\t\tKuujjuaq (Québec)  J0M 1C0\n\t\t\t819-964-2968"                         
[15] "Société aéroportuaire de Schefferville\n\t\t\t78 Atlantic Road\n\t\t\tSchefferville (Québec)  G0G 2T0\n\t\t\t418-585-3544"    
[16] "Transports Canada\n\t\t\ta/s du conseil de bande\n\t\t\tWemindji (Québec)  J0M 1L0\n\t\t\t819-978-3936"                       
[17] "Transports Canada\n\t\t\t2 Airport Road\n\t\t\tWabush (Terre-Neuve)  A0R 1B0\n\t\t\t709-282-5412"                             
[18] "Transports Canada\n\t\t\t1 Airport Road\n\t\t\tSt. Anthony (Terre-Neuve)  A0K 4S0\n\t\t\t709-454-3192"                        
[19] "Administration aéroportuaire de Victoria"                                                                                     
[20] "Administration de l’aéroport international de Vancouver"                                                                      
[21] "Administration aéroportuaire de Prince George Inc. (en anglais seulement)"                                                    
[22] "Ville de Kelowna (en anglais seulement)"                                                                                      
[23] "Administration des aéroports régionaux d’Edmonton (en anglais seulement)"                                                     
[24] "Administration aéroportuaire de Calgary (en anglais seulement)"                                                               
[25] "Administration aéroportuaire de Saskatoon (en anglais seulement)"                                                             
[26] "Administration aéroportuaire de Regina"                                                                                       
[27] "Administration aéroportuaire de Winnipeg Inc."                                                                                
[28] "Administration de l’aéroport international de Thunder Bay Inc. (en anglais seulement)"                                        
[29] "Administration de l’aéroport international du Grand London (en anglais seulement)"                                            
[30] "Autorité aéroportuaire du Grand Toronto"                                                                                      
[31] "Administration de l’aéroport international Macdonald-Cartier d'Ottawa"                                                        
[32] "Aéroports de Montréal"                                                                                                        
[33] "Aéroports de Montréal"                                                                                                        
[34] "Aéroport de Québec Inc."                                                                                                      
[35] "Administration de l’aéroport international de Fredericton"                                                                    
[36] "Administration de l’aéroport international du Grand Moncton Inc."                                                             
[37] "Aéroport de Saint John Inc."                                                                                                  
[38] "Administration de l’aéroport de Charlottetown Inc. (en anglais seulement)"                                                    
[39] "Administration de l’aéroport international de Halifax"                                                                        
[40] "Administration de l’aéroport international de Gander Inc. (en anglais seulement)"                                             
[41] "Administration de l’aéroport international de St. John’s"                                                                     
[42] "Gouvernement des Territoires du Nord-Ouest"                                                                                   
[43] "Gouvernement du Nunavut"                                                                                                      
[44] "Gouvernement du Yukon"                                                                                                        

À vous de jouer!