regex R - извлечь строку между запятыми

Так как мой CSV-файл поврежден, я читаю его в R, используя:

dataDT <- data.table::fread(".../test.csv", sep = NULL)

И он дает набор данных примерно такой:

dataDT <- data.table("ColA,ColB,ColC,ColD" = c("1,10,some text... , some text,,20190801",
                                               "2,22,some text... , some text,,20190801",
                                               "3,30,some text... , some text,,20170601"))
dataDT
> dataDT
                       ColA,ColB,ColC,ColD
1: 1,10,some text... , some text,,20190801
2: 2,22,some text... , some text,,20190801
3: 3,30,some text... , some text,,20170601

Теперь, что я хочу это разделить строку в каждой строке на 4 новых столбца :

targetDT <- data.table(ColA = c(1,2,3), 
                       ColB = c(10,22,30), 
                       ColC = c("some text... , some text,", "some text... , some text,", "some text... , some text,"),
                       ColD = c("20190801","20190801",'20170601'))
targetDT
> targetDT
   ColA ColB                      ColC     ColD
1:    1   10 some text... , some text, 20190801
2:    2   22 some text... , some text, 20190801
3:    3   30 some text... , some text, 20170601

Логика будет такой:

  • ColA имеет строку перед 1-й запятой;
  • В ColB есть все между 1-й и 2-й запятой,
  • В ColD есть строка после последней запятой;
  • В ColC есть строка в средней части (она может содержать дополнительные запятые ).

Как добиться вышеописанной логики?

Edit_1:

Чувствительные данные, извините, я не могу предоставить точные данные. Это выглядит следующим образом:

        ID,Code1,Project_Name,Report_Date
1:     123123,1, A & B,20100101
2:     1413,2, C, D and E,20120101
3: 53163,333, F, G,20140303
4: 23453,44,This is a name,20160801
5: 12645,555,5th test, to continue,20190501

Итак, все, что находится до 1-й запятой, определенно является числами, как и все между 1-й и 2-й запятой. Все, что идет после последней запятой, определенно является 8-значным числом, похожим на дату. Средняя часть может содержать несколько запятых, но без кавычек (что, я думаю, является причиной того, что fread рассматривает запятую как разделитель).

1
задан LeGeniusII 27 June 2019 в 00:30
поделиться

3 ответа

Решение с использованием stringr

library(data.table)
library(stringr)
library(dplyr)

dataDT <- data.table(data = c("1,10,some text... , some text,,20190801",
                               "2,22,some text... , some text,,20190801",
                               "3,30,some text... , some text,,20170601"))

dataDT <- dataDT %>% 
    mutate(
        ColA = str_extract(data, "^[^,]*(?=,)"),
        ColB = str_extract(data, "(?<=,)[^,]*(?=,)"),
        ColD = str_extract(data, "(?<=,)[^,]*$"),
        ColC = str_sub(data, nchar(ColA)+nchar(ColB)+3, nchar(data)-nchar(ColD)-1)
    ) %>% 
    select(ColA, ColB, ColC, ColD)

dataDT
#>   ColA ColB                      ColC     ColD
#> 1    1   10 some text... , some text, 20190801
#> 2    2   22 some text... , some text, 20190801
#> 3    3   30 some text... , some text, 20170601

Создано в 2019-06-27 с помощью пакета представитель (v0.3.0)

1
ответ дан Simon Woodward 27 June 2019 в 00:30
поделиться

Вот regex шаблон, который позволит Вам заменять символами запятой, которые смежны с выводом два и терминальные числовые значения и разделяют их друг от друга и сопроводительного текста с пробелами. Могло бы быть более безопасно использовать непробел для разделения, так как мой следующий шаг должен будет считать эти "строки" с одним из read.* функции или возможно fread снова. Возможно, с помощью "|" как разделитель?

sub("(\\d+)[,](\\d+)[,](.+)[,](\\d+)$", 
    "\\1 \\2 '\\3' \\4", 
    dataDT$"ColA,ColB,ColC,ColD" )

[1] "1 10 'some text... , some text,' 20190801" "2 22 'some text... , some text,' 20190801"
[3] "3 30 'some text... , some text,' 20170601"

круглые скобки в шаблоне используются для создания "классов получения", и в каждом случае я "получил" произвольное число цифр или десятичных разделителей с "\d +" шаблон. Я также окружил текст (полученный с ". +") с одинарными кавычками на шаблоне замены, таким образом, "внутренние пространства" в третьем column-want-to-be не были бы считаны как разделители. "\\1", "\\2", и т.д., ссылки назад на полученные символы в каждом из классов получения, заказанных в последовательности их появлений в шаблоне. См. ?regex. Однако одинарные кавычки не были бы необходимы при использовании другого разделителя.

Вот тестовое использование "|" как sep.

fread(text =sub("(\\d+)[,](\\d+)[,](.+)[,](\\d+)", "\\1|\\2|'\\3'|\\4", dataDT$"ColA,ColB,ColC,ColD" ) ,sep="|")
   V1 V2                          V3       V4
1:  1 10 'some text... , some text,' 20190801
2:  2 22 'some text... , some text,' 20190801
3:  3 30 'some text... , some text,' 20170601

Примечание: Если Ваши числовые значения имеют запятые или имеют ведущую или запаздывающую валюту, необходимо измениться пример начиная с использования "\\d" для получения числовых групп символов больше не будет успешно выполняться.

5
ответ дан 42- 27 June 2019 в 00:30
поделиться

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

В качестве альтернативы, могут быть рассмотрены позиции столбцов. Как указывал ОП

  • ColA имеет строку перед 1-й запятой;
  • ColB имеет все между 1 и 2 запятой;
  • У ColD есть строка после последней запятой;
  • ColC имеет строку в средней части (она может содержать дополнительные запятые).

Идея состоит в том, чтобы прочитать файл, используя fread() с sep = ",", как обычно, что приводит к смещению набора данных. После преобразования в длинный формат можно определить первый, второй и последний столбцы, а также промежуточные столбцы на строку . Этим записям можно присвоить имя соответствующего столбца. Во время окончательного преобразования в широкоформатный формат промежуточные столбцы свернуты в ColC.

library(data.table)
# read file
DT <- fread("
1,10,some text...  some text,,20190801
2,22,some text... , some text,,20190801
3,30,some text... ,, some text,,20170601"
            , sep = ","
            , fill = TRUE
            , header = FALSE
            , strip.white = FALSE)

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

Результатом операции чтения является выровненный и рваный набор данных:

DT
   V1 V2                      V3         V4         V5       V6       V7
1:  1 10 some text...  some text              20190801       NA       NA
2:  2 22           some text...   some text            20190801       NA
3:  3 30           some text...              some text       NA 20170601
cols <- c("ColA", "ColB", "ColC", "ColD")
# reshape from wide to long format
long <- melt(DT[, rn := .I], "rn", na.rm = TRUE)
# create lookup table to rename column names  
lut <- long[, .(variable, col = rep(cols, c(1L, 1L, .N - 3, 1L))), by = rn]
# rename columns by an update join
long[lut,  on = .(rn, variable), variable := col][]
# reshape and collapse 
dcast(long, rn ~ variable, paste, collapse = ",")
   ColA ColB                      ColC     ColD
1:    1   10  some text...  some text, 20190801
2:    2   22 some text... , some text, 20190801
3:    3   30 some text... ,, some text 20170601

Подход можно лучше объяснить, если мы посмотрим на промежуточные результаты.

После melt(), long равно

    rn variable                   value
 1:  1       V1                       1
 2:  2       V1                       2
 3:  3       V1                       3
 4:  1       V2                      10
 5:  2       V2                      22
 6:  3       V2                      30
 7:  1       V3 some text...  some text
 8:  2       V3           some text... 
 9:  3       V3           some text... 
10:  1       V4                        
11:  2       V4               some text
12:  3       V4                        
13:  1       V5                20190801
14:  2       V5                        
15:  3       V5               some text
16:  2       V6                20190801
17:  3       V7                20170601

Из этого создается таблица соответствия lut

    rn variable  col
 1:  1       V1 ColA
 2:  1       V2 ColB
 3:  1       V3 ColC
 4:  1       V4 ColC
 5:  1       V5 ColD
 6:  2       V1 ColA
 7:  2       V2 ColB
 8:  2       V3 ColC
 9:  2       V4 ColC
10:  2       V5 ColC
11:  2       V6 ColD
12:  3       V1 ColA
13:  3       V2 ColB
14:  3       V3 ColC
15:  3       V4 ColC
16:  3       V5 ColC
17:  3       V7 ColD

После присоединения обновления и перед преобразованием обратно в широкоформатный формат long выглядит как

    rn variable                   value
 1:  1     ColA                       1
 2:  2     ColA                       2
 3:  3     ColA                       3
 4:  1     ColB                      10
 5:  2     ColB                      22
 6:  3     ColB                      30
 7:  1     ColC some text...  some text
 8:  2     ColC           some text... 
 9:  3     ColC           some text... 
10:  1     ColC                        
11:  2     ColC               some text
12:  3     ColC                        
13:  1     ColD                20190801
14:  2     ColC                        
15:  3     ColC               some text
16:  2     ColD                20190801
17:  3     ColD                20170601

Теперь элементы данных выровнены по соответствующим именам столбцов. .

0
ответ дан Uwe 27 June 2019 в 00:30
поделиться
  • 1
    В то время как этот код может ответить на вопрос, обеспечив дополнительный контекст относительно того, почему и/или то, как этот код отвечает на вопрос, улучшает его долговременную ценность. – Alex Riabov 10 July 2018 в 07:16
  • 2
    В то время как этот код может ответить на вопрос, обеспечив дополнительный контекст относительно того, почему и/или то, как этот код отвечает на вопрос, улучшает его долговременную ценность. – Alex Riabov 10 July 2018 в 07:16
  • 3
    В то время как этот код может ответить на вопрос, обеспечив дополнительный контекст относительно того, почему и/или то, как этот код отвечает на вопрос, улучшает его долговременную ценность. – Alex Riabov 10 July 2018 в 07:16
  • 4
    В то время как этот код может ответить на вопрос, обеспечив дополнительный контекст относительно того, почему и/или то, как этот код отвечает на вопрос, улучшает его долговременную ценность. – Alex Riabov 10 July 2018 в 07:16
  • 5
    В то время как этот код может ответить на вопрос, обеспечив дополнительный контекст относительно того, почему и/или то, как этот код отвечает на вопрос, улучшает его долговременную ценность. – Alex Riabov 10 July 2018 в 07:16
  • 6
    В то время как этот код может ответить на вопрос, обеспечив дополнительный контекст относительно того, почему и/или то, как этот код отвечает на вопрос, улучшает его долговременную ценность. – Alex Riabov 10 July 2018 в 07:16
  • 7
    В то время как этот код может ответить на вопрос, обеспечив дополнительный контекст относительно того, почему и/или то, как этот код отвечает на вопрос, улучшает его долговременную ценность. – Alex Riabov 10 July 2018 в 07:16
  • 8
    В то время как этот код может ответить на вопрос, обеспечив дополнительный контекст относительно того, почему и/или то, как этот код отвечает на вопрос, улучшает его долговременную ценность. – Alex Riabov 10 July 2018 в 07:16
  • 9
    В то время как этот код может ответить на вопрос, обеспечив дополнительный контекст относительно того, почему и/или то, как этот код отвечает на вопрос, улучшает его долговременную ценность. – Alex Riabov 10 July 2018 в 07:16
Другие вопросы по тегам:

Похожие вопросы: