如何从字符串的开始到倒数第二个点剪切字符串?

How to cut string from start to second last dot of the string?

我有一些字符串,例如:

cats, e.g. Barsik, are funny. And it is true. So,

我想得到结果:

cats, e.g. Barsik, are funny.

我的尝试:

mb_ereg_search_init($text, '((?!e\.g\.).)*\.[^\.]');
$match = mb_ereg_search_pos();

但是它得到第二个点的位置(在单词 "true" 之后)。

如何得到想要的结果?

这里有两种获取子字符串的方法,从初始字符串的开始到倒数第二个 . 位置:

  • 使用strrpossubstr函数:

    $str = 'cats, e.g. Barsik, and e.g. Lusya are funny. And it is true. So,';
    $len = strlen($str);
    $str = substr($str, 0, (strrpos($str, '.', strrpos($str, '.') - $len - 1) - $len) + 1);
    
    print_r($str);  // "cats, e.g. Barsik, and e.g. Lusya are funny."
    
  • 使用 array_reversestr_splitarray_search 函数:

    $str = 'cats, e.g. Barsik, and e.g. Lusya are funny. And it is true. So,';
    $parts = array_reverse(str_split($str));
    $pos = array_search('.', $parts) + 1;
    $str = implode("", array_reverse(array_slice($parts, array_search('.', array_slice($parts, $pos)) + $pos)));
    
    print_r($str);  // "cats, e.g. Barsik, and e.g. Lusya are funny."
    

由于天真的方法适合您,因此我发布了一个答案。但是,请注意,检测句子结尾对于正则表达式来说是一项非常困难的任务,尽管在某种程度上是可能的,但应该使用 NLP 包来完成。

话虽如此,我建议使用

'~(?<!\be\.g)\.(?=\s+\p{Lu})~ui'

正则表达式匹配任何点 (\.),它前面没有一个完整的单词 e.g(请参阅负向回顾 (?<!\be\.g)),但后面跟有 1 个或多个空格 (\s+) 后跟 1 个大写 Unicode 字母 \p{Lu}.

regex demo

不区分大小写的 i 修饰符不会影响 \p{Lu} 匹配的内容。

需要 ~u 修饰符,因为您使用的是 Unicode 文本(如俄语)。

要获取第一次出现的索引,请使用带有 PREG_OFFSET_CAPTURE 标志的 preg_match 函数。这是您在评论中提供的稍微简化的正则表达式:

preg_match('~(?<!т\.н)(?<!т\.к)(?<!e\.g)\.(?=\s+\p{L})~iu', $text, $match, PREG_OFFSET_CAPTURE);

看到前瞻是一个接一个地执行的,并且在字符串中的相同位置,因此,您不必将它们另外分组到正前瞻中。见 regex demo.

IDEONE demo:

$re = '~(?<!т\.н)(?<!т\.к)(?<!e\.g)\.(?=\s+\p{L})~iu';
$str = "cats, e.g. Barsik, are funny. And it is true. So,"; 
preg_match($re, $str, $match, PREG_OFFSET_CAPTURE);
echo $match[0][1];