使用 tidyr::extract 正则表达式将字符串分成几列
Break string into several columns using tidyr::extract regex
我正在尝试使用 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"
- 要转到 var "x" 的第二个数字或 $Char1 项(可以是 $Char2 等)。我想 ([0-9]+|$Char[0-9]+) 可以 select 这个吗?
- 最后,“/* ... /”之间的任何内容都会转到变量 "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
以上正则表达式不完整。另外,我不知道在 extract 命令语法中明确说明哪些部分要恢复,哪些部分要删除。
在使用的正则表达式中,我们再匹配一个标点字符 ([[:punct:]]+
),即 @
,然后捕获数字部分((\d+)
- 这将是我们的第一列感兴趣的),然后是一个或多个 white-space(\s+
),然后是第二个捕获组(\S+
- 一个或多个非 white-space 字符,即 "ANO_CENSO" 第一行),然后是 space(\s+
),然后我们捕获第三组(([[:alum:]$]+)
- 即一个或多个包含字母数字和 [=18 的字符=] 以便匹配 $Char1
),接下来我们匹配一个或多个不是字母的字符([^A-Za-z]+
- 这应该去掉 space 和 *
)最后一部分我们捕获一个或多个不是 *
(([^*]+)
.
的字符
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
这是另一个选项,尽管它使用 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.
这假设 "remaining parts"(除了标签)是 space-separated。
这也可以在一个块中完成(这就是我会做的):
sasdic[, c("a","label","int_pos","var_name","x") := {
x = tstrsplit(a, "/\*|\*/")
x1s = tstrsplit(gsub("^@","",x[[1]])," +")
c(list(NULL), x1s, x[2])
}]
您可以使用包 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
我正在尝试使用 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"
- 要转到 var "x" 的第二个数字或 $Char1 项(可以是 $Char2 等)。我想 ([0-9]+|$Char[0-9]+) 可以 select 这个吗?
- 最后,“/* ... /”之间的任何内容都会转到变量 "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
以上正则表达式不完整。另外,我不知道在 extract 命令语法中明确说明哪些部分要恢复,哪些部分要删除。
在使用的正则表达式中,我们再匹配一个标点字符 ([[:punct:]]+
),即 @
,然后捕获数字部分((\d+)
- 这将是我们的第一列感兴趣的),然后是一个或多个 white-space(\s+
),然后是第二个捕获组(\S+
- 一个或多个非 white-space 字符,即 "ANO_CENSO" 第一行),然后是 space(\s+
),然后我们捕获第三组(([[:alum:]$]+)
- 即一个或多个包含字母数字和 [=18 的字符=] 以便匹配 $Char1
),接下来我们匹配一个或多个不是字母的字符([^A-Za-z]+
- 这应该去掉 space 和 *
)最后一部分我们捕获一个或多个不是 *
(([^*]+)
.
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
这是另一个选项,尽管它使用 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.
这假设 "remaining parts"(除了标签)是 space-separated。
这也可以在一个块中完成(这就是我会做的):
sasdic[, c("a","label","int_pos","var_name","x") := {
x = tstrsplit(a, "/\*|\*/")
x1s = tstrsplit(gsub("^@","",x[[1]])," +")
c(list(NULL), x1s, x[2])
}]
您可以使用包 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