为什么这个Regex.Replace无法正常工作?

时间:2012-02-01 20:35:42

标签: c# regex

我正在尝试使用以下代码将1234567890123456替换为************3456

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", "***");
    }
   }
}

2 个答案:

答案 0 :(得分:3)

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

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

修改:此版本更接近您的代码。但是,它不是依赖于预先设置的a.Value,而是使用match变量来允许您对正则表达式中实际捕获的内容应用转换。

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, …

编辑:我完成了您现在完成的代码,我意识到您甚至不需要正则表达式来完成您要完成的任务,因为您要替换属性值整体。以下是我将如何调整您的代码(通过一些更改):

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();

答案 1 :(得分:0)

您可以使用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