php regex,用于分离粘贴在左侧、右侧或在中间的字符


php regex to separate out characters stuck to left, right or in the middle

正在寻找一个php正则表达式,它将允许我从单词中分离出某些字符(如果它们位于单词的左侧或右侧,甚至位于单词内的任何位置)。

例如,

hello. -> hello .
.hello -> . hello
hello.hello -> hello . hello

我有下面的代码,但它不适用于所有情况。请注意,$value可以是"."、"?"、,或任何字符。

$regex = "/(?<='S)''" . $value . "|''" . $value . "(?='S)/";
$this->str = preg_replace_callback($regex, function($word) {
    return ' ' . $word[0];
}, $this->str);

此外,请帮助指定我可以打开(或关闭)第三个条件的部分。

[更新]我认为可能会对确切的要求感到困惑。让我试着说得更具体一些。我想要一个正则表达式,它将帮助我分离出一组文本的末尾或开头的某些字符。什么是文本组?文本组可以是任何长度(>=1)并包含任何字符,但必须以a-z或0-9开头。同样,如果这个方面能在解决方案中突出显示,那么如果我们想要一组文本以&以更多字符结尾(不仅仅是a-z或0-9)是可能的。

$character = '.', string is ".hello.world." => ". hello.world ."
$character = '.', string is ".1ello.worl2." => ". 1ello.worl2 ."
$character = '.', string is ".?1ello.worl2." => ".?1ello.worl2 ."
$character = '.', string is "4/5.5" => "4/5.5"
$character = '.', string is "4.?1+/5" => "4.?1+/5"
$character = '.', string is ".4/5.5." => ". 4/5.5 ."
$character = '/', string is ".hello?.world/" => ".hello?.world /"
$character = '/', string is ".hello?.worl9/" => ".hello?.worl9 /"

希望,现在更清楚了。

您可以使用3个备选方案,每个备选方案都被捕获到自己的捕获组中,并使用preg_replace_callback应用相应的替换:

$wrd = ".";
$re = '~(?<='S)(' . preg_quote($wrd) . ')(?='S)|(?<='S)(' . preg_quote($wrd) . ')|(' . preg_quote($wrd) . ')(?='S)~'; 
$str = "hello.'n.hello'nhello.hello"; 
$result = preg_replace_callback($re, function($m) {
    if (!empty($m[1])) {
        return " " . $m[1] . " ";
    } else if (!empty($m[2])) {
        return " " . $m[2];
    } else return $m[3] . " ";
}, $str);
echo $result;

查看IDEONE演示

正则表达式将是

(?<='S)('.)(?='S)|(?<='S)('.)|('.)(?='S)
       | 1|             | 2|  | 3|   

参见regex演示

第一组为病例3(hello.hello -> hello . hello),第二组为病例1(hello. -> hello .),第三组为病例2(.hello -> . hello)。

更新(处理异常)

如果有异常,可以添加更多的捕获组。例如,您希望保护浮点数中的点。添加一个('d'.'d)替代项,并在回调函数内部检查它是否为空。如果没有,只需使用return $m[n]:恢复即可

$wrd = ".";
$re = '~('d'.'d)|(?<='S)(' . preg_quote($wrd) . ')(?='S)|(?<='S)(' . preg_quote($wrd) . ')|(' . preg_quote($wrd) . ')(?='S)~'; 
$str = "hello.'n.hello'nhello.hello'nhello. 3.5/5'nhello.3'na./b"; 
$result = preg_replace_callback($re, function($m) {
    if ( !empty($m[1])) {         // The dot as a decimal separator
        return $m[1];             // No space is inserted
    }
    else if (!empty($m[2])) {     // A special char is enclosed with non-spaces
        return " " . $m[2] . " "; // Add spaces around
    } else if (!empty($m[3])) {   // A special char is enclosed with non-spaces
        return " " . $m[3];       // Add a space before the special char
    } else return $m[4] . " ";    // A special char is followed with a non-space, add a space on the right
}, $str);
echo $result;

查看更新的代码演示

另一个代码演示-基于.前后没有空格的匹配位置(并保护浮点值)(基于@bobblebubble的解决方案(已删除)):

$wrd = ".";
$re = '~('d'.'d)|(?<!'s)(?=' . preg_quote($wrd) . ')|(?<=' . preg_quote($wrd) . ')(?!'s)~'; 
$str = "hello.'n.hello'nhello.hello'nhello. 3.5/5'nhello.3'na./b"; 
$result = preg_replace_callback($re, function($m) {
    if ( !empty($m[1])) {         // The dot as a decimal separator
        return $m[1];             // No space is inserted
    }
    else return " ";   // Just insert a space
}, $str);
echo $result;

摘要

  • 您不能使用'b,因为您的./?等可以出现在混合的"单词"answers"非单词"上下文中
  • 您需要使用捕获和preg_replace_callback,因为有不同的替换方案

您可以使用基于单词边界的正则表达式。

'b(?='.(?!'S))|(?<=(?<!'S)'.)'b

如果后面没有非空白'S或前面没有使用查找表检查的非空白,将匹配单词和文字点之间的边界(零宽度)。

请参阅regex101中的演示。在带有参数的PHP函数中使用,并替换为空格。

// $v = character
function my_func($str, $v=".")
{
  $v = preg_quote($v, '/');
  return preg_replace('/'b(?='.$v.'(?!'S))|(?<=(?<!'S)'.$v.')'b/', " ", $str);
}

在eval.in 上的PHP演示

据我所知,.可以是任何非单词字符。如果是这样的话,试试这个:

$patron = '/('W+)/';
$this->str = trim(preg_replace($patron, ' $1 ', $this->str));

('s?[.]'s?)

如果您使用上面的regex,您可以简单地将所有匹配项替换为" . "

工作原理:

我使用's?来捕获前导和尾随空白(如果有的话)。

[.]是一个char类,因此您应该添加所有想要查找的"特定字符"。


捕获前两个条件而不捕获第三个条件的正则表达式是('s[.]'s?|'s?[.]'s)。(同样,您需要用" . "替换捕获,并将您的"特定字符"添加到char类中。)

然后,您可以选择要使用的正则表达式。