提取字符串中第一个点之前的字符

4

我想从一列字符串中提取第一个句点前面的字符。 我可以使用下面的代码来完成。尽管如此,该代码似乎过于复杂,而且我不得不采用for-loop。 有没有更简单的方法?我特别感兴趣的是正则表达式解决方案。

请注意,找到每个字符串中的最后一个数字对我的真实数据无效,尽管这种方法适用于此示例。

谢谢您的建议。

my.data <- read.table(text = '
     my.string  state
     .........    A
     1........    B
     112......    C
     11111....    D
     1111113..    E
     111111111    F
     111111111    G
', header = TRUE, stringsAsFactors = FALSE)

desired.result <- c(NA,1,2,1,3,NA,NA)

确定第一个点的位置:

my.data$first.dot <- apply(my.data, 1, function(x) {     
                                as.numeric(gregexpr("\\.", x['my.string'])[[1]])[1]
                          })

分割字符串:

split.strings <- t(apply(my.data, 1, function(x) { (strsplit(x['my.string'], '')[[1]]) } ))

my.data$revised.first.dot <- ifelse(my.data$first.dot < 2, NA, my.data$first.dot-1)

提取第一个小数点前面的字符:
for(i in 1:nrow(my.data)) {
     my.data$character.before.dot[i] <- split.strings[i,my.data$revised.first.dot[i]]
}

my.data

#   my.string state first.dot revised.first.dot character.before.dot
# 1 .........     A         1                NA                 <NA>
# 2 1........     B         2                 1                    1
# 3 112......     C         4                 3                    2
# 4 11111....     D         6                 5                    1
# 5 1111113..     E         8                 7                    3
# 6 111111111     F        -1                NA                 <NA>
# 7 111111111     G        -1                NA                 <NA>

以下是相关帖子:

在字符串中查找字符位置

6个回答

4
使用下面的正则表达式,并不要忘记启用perl=TRUE参数。
^[^.]*?\K[^.](?=\.)

在R中,正则表达式应该是这样的:
^[^.]*?\\K[^.](?=\\.)

DEMO

> library(stringr)
> as.numeric(str_extract(my.data$my.string, perl("^[^.]*?\\K[^.](?=\\.)")))
[1] NA  1  2  1  3 NA NA

模式解释:

  • ^ 断言我们在开头。
  • [^.]*? 非贪婪匹配任何字符,直到第一个点。
  • \K 丢弃先前匹配的字符。
  • [^.] 我们要匹配的字符不能是点。
  • (?=.) 并且这个字符后面必须跟着一个点。所以它匹配的字符是第一个点之前存在的字符。

1
很好,我总是忘记\K - Tim Pietzcker

3

最简单的正则表达式是^([^.])+(?=\.)

^      # Start of string
(      # Start of group 1
 [^.]  # Match any character except .
)+     # Repeat as many times as needed, overwriting the previous match
(?=\.) # Assert the next character is a .

在regex101.com上测试它。

第一个组的内容将是您所需的字符。虽然我不太懂R语言,但根据RegexBuddy,以下内容应该有效:

matches <- regexpr("^([^.])+(?=\\.)", my.data, perl=TRUE);
result <- attr(matches, "capture.start")[,1]
attr(result, "match.length") <- attr(matches, "capture.length")[,1]
regmatches(my.data, result)

2
在这个例子中,所有内容都是数字和句点。
library(stringr)
as.numeric(str_extract(my.data$my.string, perl('\\d(?=\\.)')))
#[1] NA  1  2  1  3 NA NA

或者使用 stringi

library(stringi)
as.numeric(stri_extract(my.data$my.string, regex='\\d(?=\\.)'))
#[1] NA  1  2  1  3 NA NA

如果是针对“常规”情况的话:
as.numeric(str_extract(my.data$my.string, perl('[^.](?=\\.)')))

2

我没有点踩,但是我在使用这些答案时遇到了一些问题,无法获得所需的desired.result。在你的情况下,我认为\.应该改为\\. - Mark Miller
它返回字符的位置。理想情况下,我可以在R中获得向量desired.result。我只需要弄清楚如何做到这一点,然后就可以了。谢谢你的答案。 - Mark Miller
@vks 楼主没有提到 Unicode 字符串,并且他提供了他的示例数据。 - Avinash Raj
@AvinashRaj 到目前为止,我还没有在这篇文章中点赞或点踩任何内容。一旦我弄清如何在基础的 R 中获取向量 desired.result,我可能会给每个答案点赞一次。 - Mark Miller

2
这里提供一个使用基础R语言和ifelse函数的解决方案:

代码如下:

res <- regexpr("[^.](?=\\.)", my.data$my.string, perl = TRUE)
ifelse(res < 1, NA, as.integer(regmatches(my.data$my.string, res)))
# [1] NA  2  1  3  1 NA NA

1

使用rex可能会使这种任务变得更简单。

my.data <- read.table(text = '
     my.string  state
     .........    A
     1........    B
     112......    C
     11111....    D
     1111113..    E
     111111111    F
     111111111    G
', header = TRUE, stringsAsFactors = FALSE)

library(rex)

re_matches(my.data$my.string,
  rex(capture(except(".")), "."))$'1'

#> [1] NA  "1" "2" "1" "3" NA  NA

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