如何从字符串的开始到倒数第二个点剪切字符串?
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" 之后)。
如何得到想要的结果?
这里有两种获取子字符串的方法,从初始字符串的开始到倒数第二个 .
位置:
使用strrpos
和substr
函数:
$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_reverse
、str_split
和 array_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}
.
不区分大小写的 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.
$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];
我有一些字符串,例如:
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" 之后)。
如何得到想要的结果?
这里有两种获取子字符串的方法,从初始字符串的开始到倒数第二个 .
位置:
使用
strrpos
和substr
函数:$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_reverse
、str_split
和array_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}
.
不区分大小写的 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.
$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];