我有一个字符变量(companies
),其观察结果如下:
我正在尝试将这些字符串分成3部分:
"."
之前的所有数字"."
和下一个数字之间的所有字符
(格式一致的#.##
)和#.##
)。 以第一个obs为例,我想要:“ 612”,“ Grt。Am。Mgt&Inv”,“ 5.01”
我尝试在rebus
中定义模式并使用str_match
,但是下面的代码仅适用于Obs#2和#3。它不能反映出字符串中间部分的所有变化来捕获其他对象。
pattern2 <- capture(one_or_more(DGT)) %R% DOT %R% SPC %R%
capture(or(one_or_more(WRD), one_or_more(WRD) %R% SPC
%R% one_or_more(WRD))) %R% SPC %R% capture(DGT %R% DOT
%R% one_or_more(DGT))
str_match(companies, pattern = pattern2)
是否有更好的方法将字符串分成这三个部分?
我对regex
不熟悉,但是我在这里看到了很多建议(我是R和Stack Overflow的新手)
答案 0 :(得分:2)
您可以使用正则表达式来分隔字符串,然后将其拆分以获取结果:
delimitedString = gsub( "^([0-9]+). (.*) ([0-9.]+)$", "\\1,\\2,\\3", companies )
do.call( 'rbind', strsplit(split = ",", x = delimitedString) )
# [,1] [,2] [,3]
#[1,] "612" "Grt. Am. Mgt. & Inv." "7.33"
#[2,] "77" "Wickes" "4.61"
#[3,] "265" "Wang Labs" "8.75"
#[4,] "9" "CrossLand Savings" "6.32"
#[5,] "228" "JPS Textile Group" "2.00"
正则表达式说明:
^[0-9]+
:在字符串的开头(即^
)由0到9的数字组成的任何模式.*
:贪婪的匹配,在上述情况下基本上是两个空格所包围的任何事物[0-9.]+$
:再次在字符串的末尾(即$
)加上数字+点括号用于表示我想捕捉正则表达式适合的 string 部分。抓住它们后,这些子字符串将折叠起来并以逗号分隔。最后,我们可以使用strsplit
函数拆分整个字符串,并使用do.call
函数绑定行
答案 1 :(得分:1)
您可以使用分组正则表达式匹配信息,而不是拆分文本,并从所需的三个组中提取信息。尝试使用此正则表达式,
(.+?)\.\s+(.+)\s+(\d+\.\d+)
这将在group1,group2和group3中捕获您的信息。
在这里,组1捕获公司信息之前的第一个数字,组2捕获公司信息,组3捕获#.##
格式的最后一个数字
检查此r代码,
companies = c("612. Grt. Am. Mgt. & Inv. 7.33")
result <- str_match(companies, pattern = "(.+?)\\.\\s+(.+)\\s+(\\d+\\.\\d+)")
result[,2]
result[,3]
result[,4]
打印
[1] "612"
[1] "Grt. Am. Mgt. & Inv."
[1] "7.33"
答案 2 :(得分:1)
使用以下正则表达式:
^(.*?)\.(.*?)(?=\d)(.*)$
三个捕获组包含所需的信息:第一个捕获组捕获所有内容,直到找到第一个'.'
;第二个捕获组捕获所有内容,直到找到一个数字(这是通过正向超前,这确保了数字不会被消耗,因为我们需要在下一组中捕获它),而第三组将捕获所有内容,直到最后。
答案 3 :(得分:1)
您可以使用3个捕获组:
([^.]+)\.\s+(\D+)\s+(\d\.\d{2})
例如
companies=c("612. Grt. Am. Mgt. & Inv. 7.33")
pattern="([^.]+)\\.\\s+(\\D+)\\s+(\\d\\.\\d{2})"
str_match(companies, pattern)
结果
[,1] [,2] [,3] [,4]
[1,] "612. Grt. Am. Mgt. & Inv. 7.33" "612" "Grt. Am. Mgt. & Inv." "7.33"
查看regex101 demo | R demo
说明
([^.]+)
在第1组中捕获匹配1次以上而不是一个点(也要不匹配换行符,请使用[^.\r\n]
)\.\s+
匹配一个点和1+倍的空白字符(\D+)
在第2组中匹配超过1次而不是数字的捕获\s+
匹配1次以上的空白字符(\d\.\d{2})
在第3组中捕获一个数字,点和2个数字(格式为#。##)答案 4 :(得分:1)
您应该能够调试所编写的正则表达式。
> as.regex(pattern2)
<regex> ([\d]+)\.\s((?:[\w]+|[\w]+\s[\w]+))\s(\d\.[\d]+)
Plug it in在regex101上,您会看到字符串并不总是匹配。右侧的说明告诉您,点和数字之间只能有1个或2个空格分隔的单词。另外,WRD
([\w]+
模式)不匹配点和非字母,数字或_
的其他任何字符。现在,您知道您需要将字符串与
^(\d+)\.(.*?)\s*(\d\.\d{2})$
请参见this regex demo。转换为Rebus:
pattern2 <- START %R% # ^ - start of string
capture(one_or_more(DGT)) %R% # (\d+) - Group 1: one or more digits
DOT %R% # \. - a dot
"(.*?)" %R% # (.*?) - Group 2: any 0+ chars as few as possible
zero_or_more(SPC) %R% # \s* - 0+ whitespaces
capture(DGT %R% DOT %R% repeated(DGT, 2)) %R% # (\d\.\d{2}) - Group 3: #.## number
END # $ - end of string
检查:
> pattern2
<regex> ^([\d]+)\.(.*?)[\s]*(\d\.[\d]{2})$
> companies <- c("612. Grt. Am. Mgt. & Inv. 7.33","77. Wickes 4.61","265. Wang Labs 8.75","9. CrossLand Savings 6.32","228. JPS Textile Group 2.00")
> str_match(companies, pattern = pattern2)
[,1] [,2] [,3] [,4]
[1,] "612. Grt. Am. Mgt. & Inv. 7.33" "612" " Grt. Am. Mgt. & Inv." "7.33"
[2,] "77. Wickes 4.61" "77" " Wickes" "4.61"
[3,] "265. Wang Labs 8.75" "265" " Wang Labs" "8.75"
[4,] "9. CrossLand Savings 6.32" "9" " CrossLand Savings" "6.32"
[5,] "228. JPS Textile Group 2.00" "228" " JPS Textile Group" "2.00"
警告:capture(lazy(zero_or_more(ANY_CHAR)))
返回([.]*?)
模式,该模式匹配尽可能少的0个或更多点,而不匹配任何0+个字符,因为rebus
具有一个错误:它使用字符类repeated
和one_or_more
包装所有zero_or_more
([
或]
)字符。这就是为什么“手动”添加(.*?)
的原因。
可以使用[\w\W]
/ [\s\S]
或[\d\D]
之类的常见结构来解决或解决此问题:
pattern2 <- START %R% # ^ - start of string
capture(one_or_more(DGT)) %R% # (\d+) - Group 1: one or more digits
DOT %R% # \. - a dot
capture( # Group 2 start:
lazy(zero_or_more(char_class(WRD, NOT_WRD))) # - [\w\W] - any 0+ chars as few as possible
) %R% # End of Group 2
zero_or_more(SPC) %R% # \s* - 0+ whitespaces
capture(DGT %R% DOT %R% repeated(DGT, 2)) %R% # (\d\.\d{2}) - Group 3: #.## number
END
检查:
> as.regex(pattern2)
<regex> ^([\d]+)\.([\w\W]*?)[\s]*(\d\.[\d]{2})$
请参见regex demo。