我想删除范围内除 D 之外的所有类型字符之后的数字,..
>.
(?:^<F=(?=.+>)|\G(?!^)).*[^d]\K[0-9]+
这能够捕获不在d之后的数字。但是,它不会一次捕获所有这些数字。它从后面捕获。当我们删除最后捕获的数字时,它从左到右匹配下一个。
8
d7
7
d7
9
D6kl>rtd7
数字先出现在 = 未被捕获之后。 1
H9D6kl>rt78d7
更新 2:将
更改为[^d]
解决此问题(?<!d)
..
>。但是在>
之后输入的数字也被捕获了。
8
d7更新 3:更改 (?=.
>) 到 (?=.+
>) 并将位置更改为 end (?:^*
(?=.*>)
解决这个问题。 它只捕获之前的数字>
预期输出:
<F=HD6kl>rt78d7
对于所有可能的情况:
输入:rt78d7
搭配:1
HD62
k3
l43
>rt78d75
输出:rt78d7
有了向前看和向后看,一个简单的字符串函数就可以满足您的要求。 POC:
<?php
$string = '<F=1H2D63k43l5>rt78d7';
echo "Original: $string\n";
echo "Expected: <F=HD6kl>rt78d7\n";
function formatString($string){
$end = $extension = strrchr( $string, '>'); // rt78d7
$chars = str_split($string);
$count = 0;
$new_string = '';
foreach ($chars as $key=>$item) {
$prev = $count-1;
if( $item == '>' ){
break;
}
if( is_numeric($item) && substr($string, $prev, 1) != 'D' ){
// do nothing
} else {
$new_string .= $item;
}
$count++;
}
return $new_string.$end;
}
$new = formatString($string);
echo "Actual: ".$new."\n";
?>
结果:
原文:
预期:
实际:
ok,我们可以将正则表达式分成两部分,稍后加入。
第 1 部分 -
((?<!D)\d+
。我们使用否定后向匹配仅匹配前面没有D
的数字。
第 2 部分 -
(?=.*?>)
。我们只匹配 =
和 >
之间的数字。假设你的字符串模板化得很好,如果我们只使用正则表达式正前瞻来寻找>
就足够了。
将它们连接起来后的最终正则表达式是
((?<!D)\d+)(?=.*?>)
.
这意味着只匹配那些前面没有
D
并且后面没有>
的数字。
片段:
<?php
$str = '<F=1H2D63k43l5>rt78d7';
$str = preg_replace('/((?<!D)\d+)(?=.*?>)/i','', $str);
var_dump($str === '<F=HD6kl>rt78d7');
您可以选择匹配
D
后跟数字:
(?:^<F=|\G(?!^)(?=[^\n>]*>))(?:D\d)?[^\d>\n]*\K\d+
说明
(?:
备选方案的非捕获组
^<F=
断言字符串的开头然后匹配<F=
|
或\G(?!^)
在上一场比赛的末尾断言当前位置,而不是在字符串的开头(?=[^\n>]*>)
正面前瞻,声明除 >
(或换行符)以外的可选字符,然后匹配 >
)
关闭非捕获组(?:D\d)?
可选择匹配一个 D
字符后跟一个数字(或使用 \d+
表示 1 个以上的数字)[^\d>\n]*
匹配数字以外的可选字符 >
或换行符(如果您不想匹配交叉线)\K
忘记到目前为止匹配的是什么\d+
匹配1个以上的数字$re = '/(?:^<F=|\G(?!^)(?=[^\n>]*>))(?:D\d)?[^\d>\n]*\K\d+/mi';
$s = '<F=1H2D63k43l5>rt78d7';
echo preg_replace($re, "", $s);
输出
<F=HD6kl>rt78d7