Xaisoft
Xaisoft

Reputation: 46591

How can I accomplish this with Regex?

I have the following xml snippets:

<CreditCard 
   name="John Doe" 
   ccnum="1234123412341234" 
   ccv="239" 
   exp="03/13">
</CreditCard>


<CreditCard>
   <name>John Doe</name>
   <ccnum>1234123412341234</ccnum>
   <ccv>239</ccv>
   <exp>03/13</exp>
</CreditCard>

The above snippets are just two of many ways the xml can store the credit card data, so here is my problem, I need to scan through an xml string and find a 16 digit number which I have already done, but after that I need to determine where the security code is, the ccv in this case which I will assume will be a 3-4 digit number within the CreditCard element or something similar and then encrypt that. My intial thought was to find the 16 digit number and then go back until I find the first beginning element and assume that that is the start of the credit card data and then go forward and search for a 3-4 digit number, but I am unsure how to go about doing that?

Let me assume I stick with Regex:

First I find the 13 - 16 digit number, so in the first example, I find:

1234123412341234, now I want to scan within there for a 3-4 digit number and that is where I am stuck.

Code:

//This encrypts 13-16 digit numbers, now I just need to encrypt the 3-4 digit security 
//code
foreach (Match cc in Regex.Matches(xml, @"\b\d{13,16}\b"))
 {

      Console.WriteLine(xml);
      Console.WriteLine(cc);
      xml = xml.Replace(cc.Value, "ENCRYPTED");
      Console.WriteLine(xml);

  }

Upvotes: 0

Views: 612

Answers (3)

Shiplu Mokaddim
Shiplu Mokaddim

Reputation: 57650

I found this regular expression.

(\\d{13,16})[<\"'].*?(?=[>\"']\\d{3,4}[<\"'])[>\"'](\\d{3,4})[<\"'];

Note: I am using regular expression as the XML schema is not regular.

I wrote this assuming following rules.

  1. Credit card number is a sequence digits of length between 13-16. Hence \d{13,16}
  2. CCV number is a sequence digits of length 3-4. Hence \d{3,4}
  3. CCV` should always appear after Credit Card number. And between these two there must be at least a single non-digit character. At least in most cases. Hence the whole pattern.

Let me know if any of my assumptions are wrong.

Sample Code

class Program
{
    static void Main(string[] args)
    {
        string data = @"<CreditCard> 
                   name=""John Doe"" 
                   ccnum=""1111123412341234"" 
                   ccv=""111"" 
                   exp=""03/13"">
                </CreditCard>


                <CreditCard>
                   <name>John Doe</name>
                   <ccnum>2222123412341234</ccnum>
                   <ccv>222</ccv>
                   <exp>03/13</exp>
                </CreditCard>

                <ResCreditCard 
                    resCreditCardRPH=""1"" 
                    cardCode=""11724"" 
                            cardType=""Credit"" 
                            cardNumber=""3333111111111111"" 
                            cardHolderName=""s"" 
                            expirationDate=""2015-03-31""
                            seriesCode=""333"" />";

        string pattern = "(\\d{13,16})[<\"'].*?(?=[>\"']\\d{3,4}[<\"'])[>\"'](\\d{3,4})[<\"']";
        Regex re = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);

        foreach (Match m in re.Matches(data))
            if (m.Success)
                Console.WriteLine(
                    "Credit Card Number={0}, CCV={1}",
                    m.Groups[1].Value,
                    m.Groups[2].Value
                 );

    }
}

Output

Credit Card Number=1111123412341234, CCV=111
Credit Card Number=2222123412341234, CCV=222
Credit Card Number=3333111111111111, CCV=333

Upvotes: 1

yas
yas

Reputation: 3620

I don't quite understand the question. I am assuming that at least you could separate each credit card as it would be enclosed in CreditCard tags. If XML parser is not an option, should be easy to come up with an expression to match open and close tags.

After finding start / end of element, I would just search within for ccnum and grab the first set of continous digits after it, and also do the same for ccv.

Upvotes: 0

Ry-
Ry-

Reputation: 224921

Not the pony again...

Is there a particular reason you can't just use XML? If there isn't, then you can just use the XML:

XmlDocument doc = new XmlDocument();
doc.LoadXml(myString);

foreach(XmlElement card in doc.GetElementsByTagName("CreditCard")) {
    // Use card.GetElementsByTagName("name")[0].InnerText, etc.
}

Upvotes: 6

Related Questions