2012-02-01 61 views
1

我想用一個正則表達式找到16位號碼的父節點,並返回整節,但不能弄清楚如何,所以給出:如何獲得正則表達式的工作?

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

我要回:

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

然後,我將使用解析xml並獲取每個屬性是一個數字並將其刪除。

我試過.*(\d{13,16}).*,但是這會得到每個角色。

一次,我做的:

XElement element = XElement.Parse(xml); // XDocument.Load(xmlFile).Root 

IEnumerable<XElement> elementsWithPossibleCCNumbers = 
     element.Descendants() 
       .Where(d => d.Attributes() 
          .Where(a => a.Value.Length == 16) 
          .Count() == 1); 

我想不通通過elementsWithPossibleCCNumbers每個屬性如何循環,例如:

foreach(var x in elementsWithPossibleCCNumbers) 
{ 
//If attribute is number, replace value with empty string 
} 

注:我刪除了int.TryParse爲現在。

我決定這樣做:

IEnumerable<XElement> elementsWithPossibleCCNumbers = 
     element.Descendants() 
       .Where(d => d.Attributes() 
          .Where(a => a.Value.Length >= 13 && a.Value.Length <= 16) 
          .Count() == 1).Select(x=>x); 


foreach(var x in elementsWithPossibleCCNumbers) 
{ 
    foreach(var a in x.Attributes()) 
    { 

    xml = xml.Replace(a.Value, new String('*',12)); 
    } 
} 

然而,如果我有一個第二元件具有16位數字的屬性,它只替換的屬性值的一部分。

+0

當談到正則表達式我平時靠禱告,咒罵,和魔術才能正常工作。 – Yuck 2012-02-01 16:03:53

+2

爲什麼不反序列化XML?或者使用LINQ to XML來準確地返回你需要的XML元素? – 2012-02-01 16:03:55

+2

如果你不想反序列化你也可以看看使用XPath。 – seanzi 2012-02-01 16:04:47

回答

3

由於您的XML可以有很大的差異,我會做類似下面的事情。

假設XML,如:

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

不可知論上下的代碼:

XElement element = XElement.Parse(xml); // XDocument.Load(xmlFile).Root 
int ccNumber; 

IEnumerable<XElement> elementsWithPossibleCCNumbers = 
     element.Descendants() 
       .Where(d => d.Attributes() 
          .Where(a => a.Value.Length == 16) 
          .Where(a => int.TryParse(a.Value, out ccNumber)) 
          .FirstOrDefault() != null); 

// Do not use ccNumber 
// Use elementsWithPossibleCCNumbers 

這可以擴展到包括一些屬性...

IEnumerable<XElement> elementsWithPossibleCCNumbers = 
     element.Descendants() 
       .Where(d => d.Attributes() 
          .Where(a => a.Value.Length == 16) 
          .Where(a => int.TryParse(a.Value, out ccNumber)) 
          .FirstOrDefault() != null 
          && d.Attributes().Count() == 5); 

有一個多種可能性,不包括使用正則表達式和硬編碼XML元素名稱。我傾向於使用正則表達式作爲最後的手段,特別是如果有更好的東西可以解析所有數據。

更新1

elementsWithPossibleCCNumbers是包含1個或多個屬性是在長度爲16位,並且是整數XML元素。既然如此,你不能告訴,所以我將其更改爲..

IEnumerable<XElement> elementsWithPossibleCCNumbers = 
     element.Descendants() 
       .Where(d => d.Attributes() 
          .Where(a => a.Value.Length == 16) 
          .Where(a => int.TryParse(a.Value, out ccNumber)) 
          .Count() == 1); 
          // Where only 1 attribute is 16 length and an int 

再次延長它...

IEnumerable<XAttribute> attributesWithPossibleCCNumbers = 
     element.Descendants() 
       .Where(d => d.Attributes() 
          .Where(a => a.Value.Length == 16) 
          .Where(a => int.TryParse(a.Value, out ccNumber)) 
          .Count() == 1) 
       .Select(e => e.Attributes() 
          .Where(a => a.Value.Length == 16) 
          .Where(a => int.TryParse(a.Value, out ccNumber)) 
          .First()); 
+0

我比你更喜歡你。 +1 – 2012-02-01 16:21:57

+0

我會給這個鏡頭。謝謝你的耐心。 – Xaisoft 2012-02-01 16:22:04

+1

非常好:+1。必須多看看XElement。沒有意識到你可以輕鬆地做這種事情! ;-) – Chris 2012-02-01 16:25:52

1

不要使用Regex來解析XML。它不適合它。

如何使用XmlDocument或XDocument來代替?

+0

我不想使用正則表達式,但XML可以有所不同。在這種情況下,它可能被稱爲CreditCard,但其他人可能會稱它爲PaymentInfo,CCInfo,CCDetails等等。 – Xaisoft 2012-02-01 16:06:24

+0

我會爲性能推薦'XDocument'。 – Aphelion 2012-02-01 16:06:33

+0

我在想我可以使用組合。首先獲取數字和該屬性的子項,然後使用XDocument解析元素 – Xaisoft 2012-02-01 16:07:15

2

嘗試使用: < [^>] + [0-9] {16} [^>] +>

編輯:這可能是更efficient- <([^> 0-9] + )([0-9] {16})([^>] +)>

+0

尼斯,這工作。現在我只需要解析屬性。你介意解釋這個正則表達式嗎? – Xaisoft 2012-02-01 16:14:40

+0

特別地,表達式中的「^」和「+」。 – Xaisoft 2012-02-01 16:18:02

+0

^是否定,+表示它被發現多於一次。這些是基本概念。你爲什麼在閱讀純文本信用卡信息的文件? – 2012-02-01 16:25:37

3

我寫了另一種方法來嘗試。正則表達式現在只驗證屬性值而不驗證XML本身。我不知道你想從這個方法中返回什麼,但是這至少會讓你開始不使用Regex for XML。

[Test] 
public void X() 
{ 
    const string xml = "<Details><CreditCard cardnum=\"123456789\" ccv=\"123\" exp=\"0212\" cardType=\"1\" name=\"joe\" /><donotfind>333</donotfind></Details>"; 

    var doc = new XmlDocument(); 
    doc.LoadXml(xml); 

    Console.WriteLine(doc.Name);; 

    foreach(XmlNode x in doc.ChildNodes) 
    { 
     ExploreNode(x); 
    } 
} 

void ExploreNode(XmlNode node) 
{ 
    Console.WriteLine(node.Name); 

    if (node.Attributes != null) 
    { 
     foreach (XmlAttribute attr in node.Attributes) 
     { 
      Console.WriteLine("\t{0} -> {1}", attr.Name, attr.Value); 

      if (attr.Value.Length == 16 && Regex.IsMatch(attr.Value, @"\d{16}")) 
      { 
       Console.WriteLine("\t\tCredit Card # found!"); 
      } 
     } 
    } 

    foreach (XmlNode child in node.ChildNodes) 
    { 
     ExploreNode(child); 
    } 
} 
+0

該方法很好,但正如我之前所說的,xml字符串會有所不同,這意味着元素和屬性將被稱爲不同的名稱。 – Xaisoft 2012-02-01 16:16:15

+0

@ Xaisoft:這裏沒有任何引用元素或屬性名稱的東西。所有東西都會關閉屬性值。 – 2012-02-01 16:16:56

+0

啊哈,我明白了,你正在檢查一個值爲16的屬性,但是你是因爲這個原因而部分使用了正則表達式嗎? – Xaisoft 2012-02-01 16:19:12