有人可以帮助您在R中使用gsub
来实现以下目标吗?
input string: a=5.00,b=120,c=0.0003,d=0.02,e=5.20, f=1200.0,g=850.02
desired output: a=5,b=120,c=0.0003,d=0.02,e=5.2, f=1200, g=850.02
实际上,如果它们都只是0,则删除小数点后的冗余0,如果存在实际分数,则不删除。
答案 0 :(得分:3)
我无法单独使用gsub
来解决此问题,但我们可以尝试在逗号上拆分输入向量,然后使用带有apply
的{{1}}函数:
gsub
我实际上打了x <- "a=5.00,b=120,c=0.0003,d=0.02,e=5.20, f=1200.0,g=850.02"
input <- sapply(unlist(strsplit(x, ",")), function(x) gsub("(?<=\\d)\\.$", "", gsub("(\\.[1-9]*)0+$", "\\1", x), perl=TRUE))
input <- paste(input, collapse=",")
input
[1] "a=5,b=120,c=0.0003,d=0.02,e=5.2, f=1200,g=850.02"
两次电话。如果数字为1,则第一个调用会删除小数点后出现的所有尾随零。第二个调用删除了杂散的小数点,对于像gsub
这样的数字,第一个调用将保留为5.00
而不是5.
,后者是我们想要的。
答案 1 :(得分:2)
要删除小数点后的尾随0,请尝试:
编辑忘记了5.00
x = c('5.00', '0.500', '120', '0.0003', '0.02', '5.20', '1200', '850.02')
gsub("\\.$" "", gsub("(\\.(|[1-9]+))0+$", "\\1", x))
# [1] "5" "0.5" "120" "0.0003" "0.02" "5.2" "1200" "850.02"
HT @TimBiegeleisen:我将输入误读为字符串向量。对于单字符串输入,转换为字符串向量,您可以调用gsub
,然后将输出折叠回单个字符串:
paste(
gsub("\\.$", "", gsub("(\\.(|[1-9]+))0+$", "\\1",
unlist(strsplit(x, ", ")))),
collapse=", ")
[1]“a = 5,b = 0.5,c = 120,d = 0.0003,e = 0.02,f = 5.2,g = 1200,h = 850.02”
答案 2 :(得分:1)
gsub
是文字处理工具,适用于字符级。它不知道任何语义解释。
但是,您特别感兴趣的是操纵这种语义解释,即文本中编码的数字的精确度。
所以使用它:解析文本中的数字,并以所需的精度写出:
parse_key_value_pairs = function (text) {
parse_pair = function (pair) {
pair = strsplit(pair, "\\s*=\\s*")[[1]]
list(key = pair[1], value = as.numeric(pair[2]))
}
pairs = unlist(strsplit(text, "\\s*,\\s*"))
structure(lapply(pairs, parse_pair), class = 'kvp')
}
as.character.kvp = function (x, ...) {
format_pair = function (pair) {
sprintf('%s = %g', pair[1], pair[2])
}
pairs = vapply(x, format_pair, character(1))
paste(pairs, collapse = ", ")
}
使用如下:
text = "a=5.00,b=120,c=0.0003,d=0.02,e=5.20, f=1200.0,g=850.02"
parsed = parse_key_value_pairs(text)
as.character(parsed)
这使用了R的几个有趣特性:
strsplit
内)。lapply
依次将解析函数应用于字符串的某些部分sprintf
格式化字符串。 sprintf
是一个从C改编的原始文本格式化工具。但它相当普遍,在我们的案例中它可以正常工作。为我们的类型提供标准通用as.character
的重载。这意味着任何接受对象并通过as.character
显示它的现有函数都可以处理我们的解析数据类型。特别是,这适用于{glue} library:
> glue::glue("result: {parsed}")
result: a = 5, b = 120, c = 0.0003, d = 0.02, e = 5.2, f = 1200, g = 850.02
答案 3 :(得分:1)
这可能不是最理想的解决方案,但出于教育目的,以下是一种使用条件正则表达式只调用一次的方法:
gsub
备注:强>
x = 'a=5.00,b=120,c=0.0003,d=0.02,e=5.20, f=1200.0,g=850.02'
gsub('(?!\\d+(?:,|$))(\\.[0-9]*[1-9])?(?(1)0+\\b|\\.0+(?=(,|$)))', '\\1', x, perl = TRUE)
# [1] "a=5,b=120,c=0.0003,d=0.02,e=5.2, f=1200,g=850.02"
是一个负面的lookbehind,在逗号或字符串结尾后匹配数字一次或多次。这有效从整体正则表达式匹配中排除模式。
(?!\\d+(?:,|$))
匹配一个文字点,一个零或更多的数字和一个数字(零除外)。 (\\.[0-9]*[1-9])?
使此模式可选,并且对于条件处理后向引用的方式至关重要。
?
是逻辑(?(1)0+\\b|\\.0+(?=(,|$)))
(?(IF)THEN|ELSE)
是(1)
部分,用于检查捕获组1是否匹配。这是指(IF)
(\\.[0-9]*[1-9])
是0+\\b
部分,仅当(THEN)
TRUE 时才会匹配。在这种情况下,只有(IF)
匹配时,正则表达式才会尝试在单词边界后一次或多次匹配
(\\.[0-9]*[1-9])
是\\.0+(?=(,|$))
部分,仅当(ELSE)
FALSE 时才会匹配。在这种情况下,只有当(IF)
没有匹配时,正则表达式才会尝试匹配一个字面点,在逗号或字符串结尾后一次或多次匹配
如果我们将2.和3.放在一起,我们会得到(\\.[0-9]*[1-9])
或(\\.[0-9]*[1-9])0+\\b
\\.0+(?=(,|$))
作为替换因此将\\1
转换为(\\.[0-9]*[1-9])0+\\b
或(\\.[0-9]*[1-9])
匹配的模式为空白。转换为:
\\.0+(?=(,|$))
至5.20
对于后者,
5.2
至5.00
和5
至1200.0