R преобразовать строку символов в фрейм данных

Вот небольшой образец более крупной строки символов, которая у меня есть (без пробелов). Он содержит вымышленные данные о лицах.

Каждый человек отделен . Для каждого человека есть 10 атрибутов.

txt = "EREKSON(Andrew,Hélène),female10/06/2011@Geneva(Switzerland),PPF,2000X007707,dist.093,Dt.043/996.BOUKAR(Mohamed,El-Hadi),male04/12/1956@London(England),PPF,2001X005729,dist.097,Dt.043/997.HARIMA(Olak,N’nassik,Gerad,Elisa,Jeremie),female25/06/2013@Paris(France),PPF,2009X005729,dist.088,Dt.043/998.THOMAS(Hajil,Pau,Joëli),female03/03/1980@Berlin(Germany),VAT,2010X006016,dist.078,Dt.043/999."

Я хотел бы проанализировать это в фрейме данных с таким количеством наблюдений, сколько есть людей и 10 столбцов для каждой переменной.

Я пытался использовать регулярное выражение и искал другие решения для извлечения текста в stackoverflow, но не смог достичь желаемого результата.

Это последний фрейм данных, который я имею в виду, на основе ввода строки символов -

result = data.frame(first_names = c('Hélène Andrew','Mohamed El-Hadi','Olak N’nassik Gerad Elisa Jeremie','Joëli Pau Hajil'),
                    family_name = c('EREKSON','BOUKAR','HARIMA','THOMAS'),
                    gender = c('male','male','female','female'),
                    birthday = c('10/06/2011','04/12/1956','25/06/2013','03/03/1980'),
                    birth_city = c('Geneva','London','Paris','Berlin'),
                    birth_country = c('Switzerland','England','France','Germany'),
                    acc_type = c('PPF','PPF','PPF','VAT'),
                    acc_num = c('2000X007707','2001X005729','2009X005729','2010X006016'),
                    district = c('dist.093','dist.097','dist.088','dist.078'),
                    code = c('Dt.043/996','Dt.043/997','Dt.043/998','Dt.043/999'))

Любая помощь приветствуется

Я думаю, вы можете пойти от следующего: library(tidyverse) txt %>% str_split("(?<=\\d)\\.(?=[A-Z])") %>% enframe %>% unnest(everything()) %>% mutate(value = str_split(value, "\\),")) %>% unnest_wider(value)...

PaulS 19.03.2022 16:00

Вроде не правильно разделил

Varun 19.03.2022 16:07

Ну, это только начало: вам нужно еще немного поработать над этим.

PaulS 19.03.2022 16:08
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
3
89
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вот решение, использующее tidyverse, которое объединяет различные stringr функции для очистки строки, прежде чем readr прочитать ее, в основном как CSV:

library(dplyr, warn.conflicts = FALSE) # for pipes

df <- 
  txt %>% 
  
  # Replace "." sep with newline
  stringr::str_replace_all(
    "\\.[A-Z]", 
    function(x) stringr::str_replace(x, "\\.", "\n")
  ) %>% 
  
  # Replace all commas in (First[,Middle1,Middle2,...]) with space
  stringr::str_replace_all(
    # Match anything inside brackets, but as few times as possible, so we don't
    # match multiple brackets
    "\\(.*?\\)", 
    # Inside the regex that was matched, replace comma with space
    function(x) stringr::str_replace_all(x, ",", " ")
  ) %>% 
  
  # Replace ( with ,
  stringr::str_replace_all("\\(", ",") %>%
  
  # Remove )
  stringr::str_remove_all("\\)") %>%
  
  # Replace @ with ,
  stringr::str_replace_all("@", ",") %>%
  
  # Remove the last "."
  stringr::str_replace_all("\\.$", "\n") %>% 
  
  # Add , after female/male
  stringr::str_replace_all("male", "male,") %>% 
  
  # Read as comma delimited file (works since string contains \n)
  readr::read_delim(
    file = .,
    delim = ",",
    col_names = FALSE,
    show_col_types = FALSE
  )

# Add names (could also be done directly in read_delim with col_names argument)
names(df) <- c(
  "family_name",
  "first_names",
  "gender",
  "birthday",
  "birth_city",
  "birth_country",
  "acc_type",
  "acc_num",
  "district",
  "code"
)

df
#> # A tibble: 4 × 10
#>   family_name first_names      gender birthday birth_city birth_country acc_type
#>   <chr>       <chr>            <chr>  <chr>    <chr>      <chr>         <chr>   
#> 1 EREKSON     Andrew Hélène    female 10/06/2… Geneva     Switzerland   PPF     
#> 2 BOUKAR      Mohamed El-Hadi  male   04/12/1… London     England       PPF     
#> 3 HARIMA      Olak N’nassik G… female 25/06/2… Paris      France        PPF     
#> 4 THOMAS      Hajil Pau Joëli  female 03/03/1… Berlin     Germany       VAT     
#> # … with 3 more variables: acc_num <chr>, district <chr>, code <chr>

Created on 2022-03-20 by the reprex package (v2.0.1)

Обратите внимание, что, вероятно, существуют более эффективные регулярные выражения, которые можно было бы использовать, но я считаю, что это проще и легче изменить позже.

Благодарю вас! Я заметил, что разделение имен некорректно, когда имена содержат специальные символы, такие как 'è' , ''' , '-' , 'è' , 'ï' , ''' и т. д.

Varun 19.03.2022 23:51

Я немного изменил ввод «txt», чтобы рассмотреть случай, когда у человека есть 3 имени (в некоторых случаях даже 4 имени существуют в исходном фрейме данных). Как код адаптируется для учета нескольких имен?

Varun 19.03.2022 23:53

Не так уж много нужно было бы изменить, только (1) регулярное выражение, которое находит имя/отчество внутри круглых скобок от принятия только английских букв до принятия всех слов, и (2) str_replace() с str_replace_all(), чтобы разрешить несколько отчеств. Я обновил свой ответ кодом, который работает с вашими новыми данными.

jpiversen 20.03.2022 07:47

Это выглядит великолепно, теперь несколько имен со специальными символами, кажется, работают хорошо! Я заметил всего несколько случаев, когда это все еще не работает. Я обновил вопрос, чтобы отразить их. Есть идеи, почему они не работают, а остальные работают?

Varun 20.03.2022 12:52

Да, \\([\\w,]\\) соответствует «словным символам» и запятым внутри скобок, поэтому он не распознал дефис в «Эль-Хади», ' в «Н'насик» и так далее. Я обновил свой ответ более общим регулярным выражением \\(.*?\\). Это будет соответствовать всему, что находится внутри скобок, но как можно меньше раз (*?). Это необходимо, так как без него можно было бы захватить несколько пар скобок одновременно.

jpiversen 20.03.2022 16:09

Спасибо. Распознает ли это общее регулярное выражение символ à?

Varun 20.03.2022 16:17

Да, точка . будет соответствовать чему угодно, кроме новой строки (\n). Поэтому, пока à находится внутри скобок, регулярное выражение распознает его. Вы можете проверить это так: stringr::str_detect("(à)", "\\(.*?\\)") (возвращает TRUE)

jpiversen 20.03.2022 16:20

Понятно, мне нужно освежить регулярное выражение. Большое спасибо! Принятие вашего ответа.

Varun 20.03.2022 16:23

Рад помочь! Регулярные выражения могут сбивать с толку. Я нахожу эту документацию по R полезной: ?stringi::about_search_regex, и я часто использую веб-сайт это для тестирования регулярных выражений. Эти ресурсы могут оказаться полезными и для вас.

jpiversen 20.03.2022 16:28

Отмеченный! Спасибо еще раз

Varun 20.03.2022 16:32

Вот аккуратное решение с функциями tidyrseparate_rows и extract:

library(tidyr)
data.frame(txt) %>%
  # separate `txt` into rows using the dot `.` *if* 
  # preceded by `Dt\\.\\d{3}/\\d{3}` as splitting pattern:
  separate_rows(txt, sep = "(?<=Dt\\.\\d{3}/\\d{3})\\.(?!$)") %>%
  extract(
          # select column from which to extract:
          txt,
          # define column names into which to extract:
          into = c("family_name","first_names","gender",
                   "birthday","birth_city","birth_country",
                   "acc_type","acc_num","district","code"),
          # describe the string exhaustively using capturing groups
          # `(...)` to delimit what's to be extracted:
          regex = "([A-Z]+)\\(([\\w,]+)\\),([a-z]+)([\\d/]+)@(\\w+)\\((\\w+)\\),([A-Z]+),(\\w+),dist.(\\d+),Dt\\.([\\d/]+)")
# A tibble: 4 × 10
  family_name first_names    gender birthday   birth_city birth_country acc_type acc_num  
  <chr>       <chr>          <chr>  <chr>      <chr>      <chr>         <chr>    <chr>    
1 EREKSON     Andrew,Peter   male   10/06/2011 Geneva     Switzerland   PPF      2000X007…
2 OBAMA       Barack,Hussian male   04/12/1956 London     England       PPF      2001X005…
3 CLINTON     Hillary        female 25/06/2013 Paris      France        PPF      2009X005…
4 GATES       Melinda        female 03/03/1980 Berlin     Germany       VAT      2010X006…
# … with 2 more variables: district <chr>, code <chr>

любой человек, который помогает любому другому человеку с регулярным выражением, заслуживает аплодисментов! Поздравляю ~ Крис

LDT 20.03.2022 09:58

Другие вопросы по теме