我正在尝试对某些输入数据进行简单替换,如下所述:
不幸的是,preg_replace_callback()无法正常工作。它给了我整行的所有比赛,而不是单个比赛。因此,更换后我需要将线重新放在一起,但是我没有足够的信息来做。例子:
<?php
echo replace("/^\d+,(.*),(.*),.*$/", "12,LOWERME,ANDME,ButNotMe")."\n";
echo replace("/^\d+-\d+-(.*) .* (.*)$/", "13-007-THISLOWER ThisNot THISAGAIN")."\n";
function replace($pattern, $data) {
return preg_replace_callback(
$pattern,
function($match) {
return strtolower($match[0]);
}, $data
);
}
https://www.tehplayground.com/hE1ZBuJNtFiHbdHO
给我12,lowerme,andme,butnotme
,但我想要12,lowerme,andme,ButNotMe
。
我知道使用$ match [0]是错误的。这只是为了说明。在闭包内部,我需要运行类似
foreach ($match as $m) { /* do something */ }
但是正如我所说,我不知道有关匹配项在输入字符串中的位置的信息,这使得无法再次将字符串重新组合在一起。
我已经遍历了PHP文档以及几次搜索,找不到解决方案。
说明:
我知道$ match [1],$ match [2] ...等包含匹配项。但是只有一个字符串,而不是位置。想象一下,在我的示例中,最后一个字符串也是ANDME而不是ButNotMe-根据正则表达式,应不进行匹配,并且应不对其应用回调。这就是为什么我首先使用正则表达式而不是字符串替换的原因。
此外,我以这种方式使用捕获组的原因是我需要替换过程是可配置的。因此,我无法对“替换#1和#2但不能替换#3”之类的东西进行硬编码。在不同的输入文件上,位置可能不同,或者可能需要替换的位置更多,并且只应更改使用的正则表达式。
因此,如果我的输入是"15,LOWER,ME,NotThis,AND,ME,AGAIN"
,我希望能够只更改正则表达式,而不是代码,并获得所需的结果。基本上,$ pattern和$ data都是可变的。
答案 0 :(得分:1)
这使用preg_match()
和PREG_OFFSET_CAPTURE
返回捕获组和原始字符串中找到它的位置的偏移量。然后,它对每个捕获组使用substr_replace()
来仅替换要更改的字符串部分-这样就避免了替换不希望更改的相似文本的任何机会...
function lowerParts (string $input, string $regex ) {
preg_match($regex, $input, $matches, PREG_OFFSET_CAPTURE);
array_shift($matches);
foreach ( $matches as $match ) {
$input = substr_replace($input, strtolower($match[0]),
$match[1], strlen($match[0]));
}
return $input;
}
echo lowerParts ("12,LOWERME,ANDME,ButNotMe", "/^\d+,(.*),(.*),.*$/");
给予...
12,lowerme,andme,ButNotMe
而且
echo lowerParts ("12,LOWERME,ANDME,LOWERME", "/^\d+,(.*),(.*),.*$/");
它给出了
12,lowerme,andme,LOWERME
编辑:
如果替换数据的长度不同,则需要将字符串切成小段并替换每个字符串。复杂的是,每次长度变化都会改变偏移量的相对位置,因此必须跟踪该偏移量是多少。此版本还具有一个参数,该参数是您要应用于字符串的过程(此示例仅传递"strtolower"
)...
function processParts (string $input, string $regex, callable $process ) {
preg_match($regex, $input, $matches, PREG_OFFSET_CAPTURE);
array_shift($matches);
$offset = 0;
foreach ( $matches as $match ) {
$replacement = $process($match[0]);
$input = substr($input, 0, $match[1]+$offset)
.$replacement.
substr($input, $match[1]+$offset+strlen($match[0]));
$offset += strlen($replacement) - strlen($match[0]);
}
return $input;
}
echo processParts ("12,LOWERME,ANDME,LOWERME", "/^\d+,.*,(.*),(.*)$/", "strtolower");
答案 1 :(得分:1)
这将起作用:
function replaceGroups(string $pattern, string $string, callable $callback)
{
preg_match($pattern, $string, $matches, PREG_OFFSET_CAPTURE);
array_shift($matches);
foreach (array_reverse($matches) as $match) {
$string = substr_replace($string, $callback($match[0]), $match[1], mb_strlen($match[0]));
}
return $string;
}
echo replaceGroups("/^\d+-\d+-(.*) .* (.*)$/", "13-007-THISLOWER ThisNot THISAGAIN", 'strtolower');