将分隔符定期插入字符串中

时间:2010-08-29 06:53:11

标签: php regex recursion

我在php中有以下字符串:

$string = 'FEDCBA9876543210';

该字符串可以包含2个或更多(我的意思是更多)十六进制字符 我想按2分组字符串:

$output_string = 'FE:DC:BA:98:76:54:32:10';

我想使用正则表达式,我想我看到了一种类似“递归正则表达式”的方法,但我记不住了。

任何帮助表示赞赏:)

5 个答案:

答案 0 :(得分:8)

如果您不需要检查内容,则无法使用正则表达式。

试试这个

$outputString = chunk_split($string, 2, ":");
// generates: FE:DC:BA:98:76:54:32:10:

您可能需要删除最后一个“:”。

或者这个:

$outputString = implode(":", str_split($string, 2));
// generates: FE:DC:BA:98:76:54:32:10

资源:

关于同一主题:

答案 1 :(得分:0)

您可以确保有两个或更多十六进制字符执行此操作:

if (preg_match('!^\d*[A-F]\d*[A-F][\dA-F]*$!i', $string)) {
  ...
}

不需要递归正则表达式。顺便说一句,递归正则表达式是一个矛盾的术语。根据定义,正则语言(正则表达式解析)不能递归。

如果您还要将两个字符成对分组,请忽略两个十六进制字符,请使用:

if (preg_match('!^[\dA-F]{2}(?::[A-F][\dA-F]{2})*$!i', $string)) {
  ...
}

现在,如果您想添加需要拖曳十六进制字符的条件,请使用positive lookahead

if (preg_match('!^(?=[\d:]*[A-F][\d:]*[A-F])[\dA-F]{2}(?::[A-F][\dA-F]{2})*$!i', $string)) {
  ...
}

为了解释这是如何工作的,它首先要做的是它检查(带有正向前瞻即(?=...)你有零个或多个数字或冒号后跟一个十六进制字母后跟零个或多个数字或冒号然后是一个字母。这将确保表达式中有两个十六进制字母。

正向前瞻是原始表达式,确保字符串是十六进制数字对。

答案 2 :(得分:0)

听起来像你想要这样的正则表达式:

/([0-9a-f]{2})/${1}:/gi

其中,在PHP中是......

<?php
$string = 'FE:DC:BA:98:76:54:32:10';
$pattern = '/([0-9A-F]{2})/gi';
$replacement = '${1}:';
echo preg_replace($pattern, $replacement, $string);
?>

请注意,上述代码目前尚未经过测试。

答案 3 :(得分:0)

递归正则表达式通常是不可能的。您可以递归使用前一个正则表达式的结果的正则表达式,但大多数正则表达式语法将不允许递归。这是正则表达式几乎总是不足以解析HTML之类的东西的主要原因。无论如何,你需要什么并不需要任何递归。

简单地说,您想要的是多次匹配一个组。这很简单:

preg_match_all("/([a-z0-9]{2})+/i", $string, $matches);

这将填充$matches所有出现的两个十六进制数字(以不区分大小写的方式)。要替换它们,请使用preg_replace:

echo preg_replace("/([a-z0-9]{2})/i", $string, '\1:');

最后可能会有一个':'太多,您可以使用substr剥离它:

echo substr(preg_replace("/([a-z0-9]{2})/i", $string, '\1:'), 0, -1);

答案 4 :(得分:0)

虽然使用rtrim(chunk_split($string, 2, ':'), ':')并不是一种可怕的做法,但我更喜欢使用直接的技术,以避免在进行修改后“扫荡”。

代码:(Demo

$string = 'FEDCBA9876543210';
echo preg_replace('~[\dA-F]{2}(?!$)\K~', ':', $string);

输出:

FE:DC:BA:98:76:54:32:10

不要被正则表达式吓倒。该模式显示:

[\dA-F]{2}   # match exactly two numeric or A through F characters
(?!$)        # that is not located at the end of the string
\K           # restart the fullstring match

当我说“重新开始全字符串匹配”时,我的意思是“忘记先前匹配的字符并从此点开始匹配”。由于\K之后没有匹配的其他字符,因此该模式有效地提供了应在其中插入冒号的零宽度位置。这样,在替换中不会丢失任何原始字符。