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
原答案
你的问题是 \b
匹配单词边界,即左边的字符是单词字符 (a-zA-Z0-9_
) 而右边的字符是非单词字符 (或相反亦然)。由于输入字符串中没有单词字符,因此永远无法匹配单词边界。相反,您可以对不是点或破折号的字符使用环视:
function morsedecode($code){
$search = array('/(?<![.-])\.-(?![.-])/', '/(?<![.-])-\.\.\.(?![.-])/');
$replace = array('a', 'b');
return preg_replace($search, $replace, $code);
}
echo morsedecode(".- -...");
输出
a b
注意.
是regex中的特殊字符(匹配任意字符)需要转义,否则会匹配-
和.
。
\b
是一个词边界,可以是以下任意一种。
- 在字符串的第一个字符之前,如果第一个字符是单词字符。
- 在字符串的最后一个字符之后,如果最后一个字符是单词字符。
- 字符串中两个字符之间,一个是单词字符,另一个不是单词字符。
'/\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);
}
我最终想出了我自己的小问题解决方案:
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 的回答绝对是一种有效的方法。
所以我正在尝试制作莫尔斯电码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
原答案
你的问题是 \b
匹配单词边界,即左边的字符是单词字符 (a-zA-Z0-9_
) 而右边的字符是非单词字符 (或相反亦然)。由于输入字符串中没有单词字符,因此永远无法匹配单词边界。相反,您可以对不是点或破折号的字符使用环视:
function morsedecode($code){
$search = array('/(?<![.-])\.-(?![.-])/', '/(?<![.-])-\.\.\.(?![.-])/');
$replace = array('a', 'b');
return preg_replace($search, $replace, $code);
}
echo morsedecode(".- -...");
输出
a b
注意.
是regex中的特殊字符(匹配任意字符)需要转义,否则会匹配-
和.
。
\b
是一个词边界,可以是以下任意一种。
- 在字符串的第一个字符之前,如果第一个字符是单词字符。
- 在字符串的最后一个字符之后,如果最后一个字符是单词字符。
- 字符串中两个字符之间,一个是单词字符,另一个不是单词字符。
'/\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);
}
我最终想出了我自己的小问题解决方案:
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 的回答绝对是一种有效的方法。