preg_replace 不适用于符号组

preg_replace not working on groups of symbols

所以我正在尝试制作莫尔斯电码encoder/decoder;我完成了编码器,但解码器给我带来了一些问题。

因此,如果我使用函数 test 并输入“ab”,它将 return “ab”。但是,如果我输入“a b”它returns“c d”(应该,100% 工作)

function test($code){
    $search = array('/\ba\b/', '/\bb\b/');
    $replace = array('c', 'd');
    return preg_replace($search, $replace, $code);
}

BUT 当我使用函数 morsedecode 并输入“.- -...”时,它什么也没做并重新调整“.- -...”。

function morsedecode($code){
    $search = array('/\b.-\b/', '/\b-...\b/');
    $replace = array('a', 'b');
    return preg_replace($search, $replace, $code);
}

我被卡住了,因为它似乎对符号不起作用,就像对字母和单词一样。有谁知道这是什么原因,是否可以在 PHP 中解决这个问题?

更新

如果您的所有字符都被空格包围(或 beginning/end 行),您可能会发现使用 strtr 比使用基于正则表达式的方法更容易。由于 strtr 首先替换最长的匹配项,因此您不必担心(例如)-.- (k) 被部分替换为 -a.

function morsedecode($code){
    $search = array('.-', '-...');
    $replace = array('a', 'b');
    return strtr($code, array_combine($search, $replace));
}

echo morsedecode(".- -...");

输出:

a b

Demo on 3v4l.org

原答案

你的问题是 \b 匹配单词边界,即左边的字符是单词字符 (a-zA-Z0-9_) 而右边的字符是非单词字符 (或相反亦然)。由于输入字符串中没有单词字符,因此永远无法匹配单词边界。相反,您可以对不是点或破折号的字符使用环视:

function morsedecode($code){
    $search = array('/(?<![.-])\.-(?![.-])/', '/(?<![.-])-\.\.\.(?![.-])/');
    $replace = array('a', 'b');
    return preg_replace($search, $replace, $code);
}

echo morsedecode(".- -...");

输出

a b

Demo on 3v4l.org

注意.是regex中的特殊字符(匹配任意字符)需要转义,否则会匹配-.

\b是一个词边界,可以是以下任意一种。

  1. 在字符串的第一个字符之前,如果第一个字符是单词字符。
  2. 在字符串的最后一个字符之后,如果最后一个字符是单词字符。
  3. 字符串中两个字符之间,一个是单词字符,另一个不是单词字符。

'/\b.-\b/' 由于#1,第一个 \b.- -... 中不匹配。具体来说 if the first character is a word character

单词字符 = ASCII letter, digit or underscore 所以 . 不是单词字符。

此外,您需要转义 . 个字符,例如 \..

尝试寻找 \s*(任意数量的空格)而不是单词边界。

function morsedecode($code){
    $search = array('/\s*\.-\s*/', '/\s*-\.\.\.\s*/');
    $replace = array('a', 'b');
    return preg_replace($search, $replace, $code);
}

例子 https://regex101.com/r/LCZXCn/1

我最终想出了我自己的小问题解决方案:

    function morsedecode($code){
        $bd_code = str_replace(array('.', '-', '/'), array('dot', 'dash', '~slash~'), $code);
        $search = array('/\bdotdash\b/', '/\bdashdotdotdot\b/', '/\bdashdotdashdot\b/', 'etc..');
        $replace = array('a', 'b', 'c', 'etc..');
        $string =  preg_replace($search, $replace, $bd_code);
        return str_replace(array(' ', '~slash~'), array('', ' '), $string);
    }

绝对不是最有效率的,但可以完成工作。 @Nick 的回答绝对是一种有效的方法。