2012-02-01 5 views
-2

Я пытаюсь заменить 123456789 с ************3456 следующим кодом:Почему это Regex.Replace не работает должным образом?

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

но я все еще получаю *** для cardnum.

Адрес электронной почты: XML. Обратите внимание, что номер карты может быть от 13 до 16 цифр, и я всегда хочу, чтобы последний 4.

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

длинные числовые;

string xml = @"<Details> 
<CreditCard cardnum='123456789' 
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", "***"); 
    } 
    } 
} 
+1

Ваше регулярное выражение просит '{13,16}' цифр, так как он не работает должным образом, когда ваша строка имеет 16 цифр? – BoltClock

+0

@BoltClock - Извините, не хорошо с регулярным выражением, но у меня было ощущение, что это что-то в этом роде. В принципе, мне нужно сопоставить число, которое составляет 13-16 цифр, но заменять все, кроме последних 4 символов. – Xaisoft

+0

Я не верю в регулярное выражение, оно работает, когда я его тестирую – msmucker0527

ответ

3

Вы можете использовать предпросмотр, чтобы соответствовать завершающие 4 цифры, но сохранить их:

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

Edit: Эта версия ближе к коду. Однако вместо того, чтобы полагаться на предварительно заданный 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)); 

Edit: Я думаю, что вы уже получили. Но, вероятно, что вам нужно сделать, это заменить:

xml = Regex.Replace(xml, … 

с:

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

Редактировать: Я прошел через свой теперь полный код, и я понял, что вы даже не нужно регулярное выражение за то, что вы пытаетесь выполнить, поскольку вы полностью заменяете значение атрибута. Вот как я бы адаптировать свой код (с рядом изменений):

string xml = @" 
    <Details> 
     <CreditCard cardnum='123456789' 
        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(); 
+0

Можете ли вы объяснить, почему мой способ не работает? и что вы имеете в виду, сохраняя их? Кроме того, что происходит в случае, когда в представлении меньше 4 цифр или больше 4. – Xaisoft

+1

Я проверил ваш код, и он тоже работает. Я предполагаю, что у вас неправильное значение в 'a.Value'. – Douglas

+0

Я пробовал это, но он возвращает 3 *, я обновляю свой пост. – Xaisoft

0

Вы можете использовать MatchEvaluator, в данном случае я использовал лямбда.

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

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

Смежные вопросы