使用tidyr::extract正则表达式将字符串拆分为多个列

8

我将尝试使用正则表达式在R中将一个字符串向量拆分为多个变量,并且最好使用tidyr :: extract命令以dplyr-tidyr的方式。例如,在下面的向量中:

sasdic <- data.frame(a=c(
  '@1   ANO_CENSO   5.  /*Ano do Censo*/',
  '@71  TP_SEXO $Char1. /*Sexo*/',
  '@72  TP_COR_RACA $Char1. /*Cor/raça*/',
  '@74  FK_COD_PAIS_ORIGEM  4.  /*Código País de origem*/' )) 

我希望实现以下内容的翻译:
  • 将第一个数字([0-9]+)赋值给变量“int_pos”
  • 将下划线连接的变量名称([a-zA-Z_]+)赋值给变量“var_name”
  • 将第二个数字或术语 $Char1(也可以是 $Char2 等)赋值给变量“x”。我想 ([0-9]+|$Char[0-9]+) 可以选择这个吗?
  • 最后,将 "/* ... /" 之间的任何内容赋值给变量"label"(不知道这个的正则表达式)。所有其他中间字符(空格、"."、"/"、"")应该被忽略。
这将是结果。
d <- data.frame(int_pos=c(1,72,72,74),
                var_name=c('ANO_CENSO','TP_SEXO','TP_COR_RACA','FK_COD_PAIS_ORIGEM'),
                x=c('5','Chart1','$Char1','4'),
                label=c('Ano do Censo','Sexo','Cor/raça','Código País de origem') )

我尝试构建一个与此相关的正则表达式。目前我得到了以下内容:

sasdic %>% extract(a, c('int_pos','var_name','x','label'), 
                   "([0-9]+)([a-zA-Z_]+)([0-9]+|$Char[0-9]+)(something to get the label") 
             -> d

以上正则表达式不完整。此外,我不知道如何在提取命令语法中明确指定要恢复哪些部分以及要留下哪些部分。

3个回答

7

这是另一种选择,不过它使用的是data.table包,而不是tidyr:

library(data.table)
setDT(sasdic)

# split label
sasdic[, c("V1","label") := tstrsplit(a, "/\\*|\\*/")]                   
# remove leading "@", split remaining parts
sasdic[, c("int_pos","var_name","x") := tstrsplit(gsub("^@","",V1)," +")]
# remove unneeded columns
sasdic[, c("a","V1") := NULL]                                            

sasdic

#                    label int_pos           var_name       x
# 1:          Ano do Censo       1          ANO_CENSO      5.
# 2:                  Sexo      71            TP_SEXO $Char1.
# 3:              Cor/raça      72        TP_COR_RACA $Char1.
# 4: Código País de origem      74 FK_COD_PAIS_ORIGEM      4.

这假设“剩余部分”(除了标签之外)是以空格分隔的。
这也可以在一个块中完成(这是我会做的事情):
sasdic[, c("a","label","int_pos","var_name","x") := {
  x   = tstrsplit(a, "/\\*|\\*/")
  x1s = tstrsplit(gsub("^@","",x[[1]])," +")
  c(list(NULL), x1s, x[2])
}]

7
在使用的正则表达式中,我们匹配一个或多个标点符号字符 ([[:punct:]]+),即 @ 后面跟着捕获数字部分((\\d+) - 这将是我们感兴趣的第一列),后面跟着一个或多个空格 (\\s+),紧接着第二个捕获组 (\\S+ - 一个或多个非空格字符,例如第一行的 "ANO_CENSO"),再后面跟着一个空格 (\\s+),然后我们捕获第三个组 (([[:alum:]$]+) - 即包括字母数字和 $ 的一个或多个字符,以匹配 $Char1),接下来我们匹配一个或多个不是字母的字符 ([^A-Za-z]+- 这应该去掉空格和 *),最后我们捕获一个或多个不是 * 的字符 (([^*]+))。
sasdic %>% 
      extract(a, into=c('int_pos', 'var_name', 'x', 'label'),
   "[[:punct:]](\\d+)\\s+(\\S+)\\s+([[:alnum:]$]+)[^A-Za-z]+([^*]+)")

#  int_pos           var_name      x                 label
#1       1          ANO_CENSO      5          Ano do Censo
#2      71            TP_SEXO $Char1                  Sexo
#3      72        TP_COR_RACA $Char1              Cor/raça
#4      74 FK_COD_PAIS_ORIGEM      4 Código País de origem

0
你可以使用包unglue:
library(unglue)
unglue_unnest(sasdic, a, "@{int_pos}{=\\s+}{varname}{=\\s+}{x}.{=\\s+}/*{label}*/")
#>   int_pos            varname      x                       label
#> 1       1          ANO_CENSO      5                Ano do Censo
#> 2      71            TP_SEXO $Char1                        Sexo
#> 3      72        TP_COR_RACA $Char1                 Cor/ra<e7>a
#> 4      74 FK_COD_PAIS_ORIGEM      4 C<f3>digo Pa<ed>s de origem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接