为什么此Regex.Replace无法正常工作

本文关键字:常工作 工作 Regex Replace 为什么 | 更新日期: 2023-09-27 18:22:14

我正试图用以下代码用************3456替换1234567890123456

Regex.Replace(xml,@"'b'd{13,16}'b", string.Concat(new String('*',12),a.Value.Substring(a.Value.Length - 4)));

其中a.Value是数字,但它只会产生:

****************

完整代码:

//Check if value is the credit card
        if(a.Value.Length >= 13 && a.Value.Length <= 16)
                xml = Regex.Replace(xml,@"'b'd{12}(?='d{4})'b", new String('*',12));
        else //If value is not a credit card, replace it with ***
            xml = Regex.Replace(xml,@"'b'd+'b", "***");

我将if语句的第一部分替换为:

Regex.Replace(xml, @"'b'd{13,16}'b", match => 
    String.Concat(new String('*', match.Length - 4), match.Value.Substring(match.Length - 4)));

但我仍然得到了卡号码的***

这是XML。请注意,卡号可以在13到16位之间,我总是想保留最后4位。

<Details>
<CreditCard cardnum='1234567890123456'
ccv='123' 
exp='0212' 
cardType='1' 
name='joe' />
</Details>

长数字;

    string xml = @"<Details>
<CreditCard cardnum='1234567890123456'
ccv='123' 
exp='0212' 
cardType='1' 
name='joe' />
</Details>";
XElement element = XElement.Parse(xml);
IEnumerable<XElement> elementsWithPossibleCCNumbers = 
        element.Descendants()
               .Where(d => d.Attributes()
                            .Where(a => a.Value.Length >= 13 && a.Value.Length <= 16)
                            .Where(a => long.TryParse(a.Value, out numeric))
                            .Count() == 1).Select(x=>x);

foreach(var x in elementsWithPossibleCCNumbers)
{
   foreach(var a in x.Attributes())
   {
    //Check if the value is a number
    if(long.TryParse(a.Value,out numeric))
    {
        //Check if value is the credit card
        if(a.Value.Length >= 13 && a.Value.Length <= 16)
            Regex.Replace(xml,@"'b'd{12}(?='d{4}'b)", new String('*',12));
        else //If value is not a credit card, replace it with ***
            xml = Regex.Replace(xml,@"'b'd+'b", "***");
    }
   }
}

为什么此Regex.Replace无法正常工作

您可以使用前瞻来匹配后面的4位数字,但保留它们:

Regex.Replace(xml,@"'b'd{12}(?='d{4}'b)", new String('*',12))

编辑:此版本更接近您的代码。但是,它不依赖于预设的a.Value,而是使用match变量来允许您将转换应用于regex中实际捕获的内容。

Regex.Replace(xml, @"'b'd{13,16}'b", match => 
    new String('*', match.Length - 4) +
    match.Value.Substring(match.Length - 4));

上面的代码假设您希望经过编辑的字符串与原始字符串的长度相同,并保留最后4位数字。

如果您想编辑前12位数字并保留剩余的数字(1-4位),请使用:

Regex.Replace(xml, @"'b'd{13,16}'b", match => 
    new String('*', 12) +
    match.Value.Substring(12));

编辑:我想你已经得到了。但你可能需要做的是替换:

xml = Regex.Replace(xml, …

带有:

a.Value = Regex.Replace(a.Value, …

编辑:我仔细阅读了您现在完整的代码,我意识到您甚至不需要regex来完成您想要完成的任务,因为您要替换整个属性值。以下是我如何调整您的代码(进行了一些更改):

string xml = @"
    <Details>
        <CreditCard cardnum='1234567890123456'
                    ccv='123' 
                    exp='0212' 
                    cardType='1' 
                    name='joe' />
    </Details>";
XElement element = XElement.Parse(xml);
IEnumerable<XElement> elementsWithPossibleCCNumbers =
    element.Descendants()
            .Where(d => d.Attributes()
                         .Select(a => a.Value)
                         .Any(v => v.Length >= 13 &&
                                   v.Length <= 16 &&
                                   v.All(Char.IsDigit)));
foreach (var x in elementsWithPossibleCCNumbers)
{
    foreach (var a in x.Attributes())
    {
        //Check if the value is a number
        if (a.Value.All(Char.IsDigit))
        {
            //Check if value is the credit card
            if (a.Value.Length >= 13 && a.Value.Length <= 16)
                a.Value = new String('*', a.Value.Length - 4) + a.Value.Substring(a.Value.Length - 4);
            else //If value is not a credit card, replace it with ***
                a.Value = "***";
        }
    }
}
xml = element.ToString();

您可以使用MatchEvaluator,在本例中,我使用了lambda。

[Test]
public void Test()
{
    string xml = "foo 1234567890123456 bar";
    Debug.WriteLine(Regex.Replace(xml, @"'b'd{9,12}(?='d{4}'b)", m => new string('*', m.Value.Length)));
}

foo ************3456 bar