在文本中删除点但不删除标记十进制点的点。

3

我是一个正则表达式的新手,请多多包涵。

我有一个字符串,像这样:

txt1 <- 'a,b,a.b,a.,1,2,1.2,1.,.,11,222,11.222,11.'

假设数据来自一个 .csv 文件,每个单元格都用 ',' 分隔。现在我想要移除所有的 '.',但是需要保留标记小数点的 '.'。最终,我希望得到类似于以下内容:

txt2 <- 'a,b,ab,a,1,2,1.2,1,,11,222,11.222,11'

我尝试了以下代码:
txt2 <- gsub(pattern = '[^a-z0-9,(\\d\\.\\d)]', replacement = '', text = txt1)
txt2 <- gsub(pattern = '[^a-z0-9,|(\\d\\.\\d)]', replacement = '', text = txt1)

但是两者都不起作用,都返回了相同的结果。
> print(txt2)
[1] "a,b,a.b,a.,1,2,1.2,1.,.,11,222,11.222,11."

有什么想法可以帮我纠正代码吗?谢谢!
3个回答

4
关键在于使用负回顾后发表达式?<!和负前瞻表达式?!
> txt1 <- 'a,b,a.b,a.,1,2,1.2,1.,.,11,222,11.222,11.'
> txt2 <- gsub(pattern='((?<![0-9])\\.)|(\\.(?![0-9]))', replacement='', x=txt1, perl=TRUE)
> txt2
[1] "a,b,ab,a,1,2,1.2,1,,11,222,11.222,11"

这个模式匹配以非0-9或点号后面跟随不是0-9的字符的句号\\.。您需要设置perl=TRUE,让R识别lookbehind和lookahead。
这将修剪前导句点字符,因此'.2'将变为'2'。如果不想要这个效果,lookbehind需要是(?<![0-9,])

在这里将\.放入捕获组的目的是什么? - CAustin
不需要使用lookbehind,参见上面两个答案。 - Maurits Evers
非常感谢您的详细解释。这对我非常有帮助! - Xiangyu
@CAustin 我编辑掉了捕获组-事实证明你不需要它。@MauritsEvers 这个后顾是为了排除像'A.2'和'.2'这样的值(看起来OP想要修剪句点字符)。如果OP想保留前导句点字符,比如'.2',那么后顾应该是(?<![0-9,]) - zambonee

0

非常感谢你的答案。链接非常有用! - Xiangyu
这里有一个后续问题,希望您也能友好地回答。由于括号 () 在列表 [] 中无法识别,那么我该如何编写代码来识别不在组中的内容?是 (?!(the group)) 是唯一的方法吗? - Xiangyu
你是在谈论一种否定整个字符串的方法,类似于 [^abc] 否定单个字符 a、b 和 c 的方式吗?没有办法完全复制它的工作方式,但可以使用负向先行断言(使用 (?! ... ),如上面的答案所示)来实现接近的效果。 - CAustin
我明白了。再次感谢您的帮助! - Xiangyu

0
负向先行断言(如@CAustin所建议)似乎是最优雅和简明的方法。
由于以上解决方案都没有提供实际的R代码,这里给出了代码示例:
txt2 <- gsub("\\.(?!\\d)", "", txt1, perl = TRUE)
[1] "a,b,ab,a,1,2,1.2,1,,11,222,11.222,11"

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