使用preg_replace进行可变长度的遮罩 [英] variable length masking with preg_replace

查看:56
本文介绍了使用preg_replace进行可变长度的遮罩的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用preg_replace_callback()屏蔽字符串中单引号(包括两端)之间的所有字符.但我只想在可能的情况下使用preg_replace(),但无法弄清楚.任何帮助将不胜感激.

这是我使用的preg_replace_callback()所产生的正确输出的结果:

function maskCallback( $matches ) {
    return str_repeat( '-', strlen( $matches[0] ) );
}
function maskString( $str ) {
    return preg_replace_callback( "('.*?')", 'maskCallback', $str );
}

$str = "TEST 'replace''me' ok 'me too'";
echo $str,"\n";
echo $maskString( $str ),"\n";

输出为:

TEST 'replace''me' ok 'me too'
TEST ------------- ok --------

我尝试使用:

preg_replace( "/('.*?')/", '-', $str );

但是破折号被消耗掉了,例如:

TEST -- ok -

我尝试过的所有其他方法也不起作用. (我显然不是正则表达式专家.)这可能吗?如果可以,怎么办?

解决方案

是的,您可以做到(假设引号是平衡的)示例:

$str = "TEST 'replace''me' ok 'me too'";
$pattern = "~[^'](?=[^']*(?:'[^']*'[^']*)*+'[^']*\z)|'~";    
$result = preg_replace($pattern, '-', $str);

这个想法是:如果字符是一个引号或后面跟一个奇数的引号,则可以替换该字符.

不带引号:

$pattern = "~(?:(?!\A)\G|(?:(?!\G)|\A)'\K)[^']~";
$result = preg_replace($pattern, '-', $str);

仅当与前一个匹配连续的字符时(换句话说,当它在最后一个匹配之后紧接时),或者当它的前面带有与该前一个匹配不连续的引号时,该模式才匹配一个字符. /p>

\G是最后一场比赛之后的位置(开始时是字符串的开头)

图案细节:

~             # pattern delimiter

(?: # non capturing group: describe the two possibilities
    # before the target character

    (?!\A)\G  # at the position in the string after the last match
              # the negative lookbehind ensure that this is not the start
              # of the string

  |           # OR

    (?:       # (to ensure that the quote is a not a closing quote)
        (?!\G)   # not contiguous to a precedent match
      |          # OR
        \A       # at the start of the string
    )
    '         # the opening quote

    \K        # remove all precedent characters from the match result
              # (only one quote here)
)

[^']          # a character that is not a quote

~

请注意,由于模式不匹配右引号,因此以下非引号的字符将无法匹配,因为没有先例匹配.

(*SKIP)(*FAIL)方式:

您可以使用回溯控制动词(*SKIP)(*FAIL)(可以是缩短为(*F)).

$pattern = "~(?:(?!\A)\G|')(?:'(*SKIP)(*F)|\K[^'])~";
$result = preg_replace($pattern, '-', $str);

由于该模式在每个右引号上均失败,因此以下字符将不匹配,直到下一个右引号.

像这样写的模式可能更有效:

$pattern = "~(?:\G(?!\A)(?:'(*SKIP)(*F))?|'\K)[^']~";

(您也可以使用(*PRUNE)代替(*SKIP).)

I am masking all characters between single quotes (inclusively) within a string using preg_replace_callback(). But I would like to only use preg_replace() if possible, but haven't been able to figure it out. Any help would be appreciated.

This is what I have using preg_replace_callback() which produces the correct output:

function maskCallback( $matches ) {
    return str_repeat( '-', strlen( $matches[0] ) );
}
function maskString( $str ) {
    return preg_replace_callback( "('.*?')", 'maskCallback', $str );
}

$str = "TEST 'replace''me' ok 'me too'";
echo $str,"\n";
echo $maskString( $str ),"\n";

Output is:

TEST 'replace''me' ok 'me too'
TEST ------------- ok --------

I have tried using:

preg_replace( "/('.*?')/", '-', $str );

but the dashes get consumed, e.g.:

TEST -- ok -

Everything else I have tried doesn't work either. (I'm obviously not a regex expert.) Is this possible to do? If so, how?

解决方案

Yes you can do it, (assuming that quotes are balanced) example:

$str = "TEST 'replace''me' ok 'me too'";
$pattern = "~[^'](?=[^']*(?:'[^']*'[^']*)*+'[^']*\z)|'~";    
$result = preg_replace($pattern, '-', $str);

The idea is: you can replace a character if it is a quote or if it is followed by an odd number of quotes.

Without quotes:

$pattern = "~(?:(?!\A)\G|(?:(?!\G)|\A)'\K)[^']~";
$result = preg_replace($pattern, '-', $str);

The pattern will match a character only when it is contiguous to a precedent match (In other words, when it is immediately after the last match) or when it is preceded by a quote that is not contiguous to the precedent match.

\G is the position after the last match (at the beginning it is the start of the string)

pattern details:

~             # pattern delimiter

(?: # non capturing group: describe the two possibilities
    # before the target character

    (?!\A)\G  # at the position in the string after the last match
              # the negative lookbehind ensure that this is not the start
              # of the string

  |           # OR

    (?:       # (to ensure that the quote is a not a closing quote)
        (?!\G)   # not contiguous to a precedent match
      |          # OR
        \A       # at the start of the string
    )
    '         # the opening quote

    \K        # remove all precedent characters from the match result
              # (only one quote here)
)

[^']          # a character that is not a quote

~

Note that since the closing quote is not matched by the pattern, the following characters that are not quotes can't be matched because there is no precedent match.

EDIT:

The (*SKIP)(*FAIL) way:

Instead of testing if a single quote is not a closing quote with (?:(?!\G)|\A)' like in the precedent pattern, you can break the match contiguity on closing quotes using the backtracking control verbs (*SKIP) and (*FAIL) (That can be shorten to (*F)).

$pattern = "~(?:(?!\A)\G|')(?:'(*SKIP)(*F)|\K[^'])~";
$result = preg_replace($pattern, '-', $str);

Since the pattern fails on each closing quotes, the following characters will not be matched until the next opening quote.

The pattern may be more efficient written like this:

$pattern = "~(?:\G(?!\A)(?:'(*SKIP)(*F))?|'\K)[^']~";

(You can also use (*PRUNE) in place of (*SKIP).)

这篇关于使用preg_replace进行可变长度的遮罩的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆