2015-03-10 2 views
0

Я должен проанализировать файлы со следующей структурой образца.NET Regex Выражения для разбора файла с разделителями

// This is a comment 
    // NotUsed : 123654 

**************************************** 
*   DESCRIPTION 
*************************************** 
Header:   xxx 
Date:   20010101  
ReqDate:20150402 
P.O.   123456 
Qty   10000 
Part Number:  xx-yy-456 
Type:   J 
Product:   xxyy123456V0.01 (bulk) 
Cust ID: 51 
Model:   
Location:  60 
UPC:   123456 
* 
cust_ref:  Hello Worlkd 
* 
*************************************** 
*   Data 
*************************************** 

Я пытаюсь использовать следующие Regex, но не захватывая ключ/значения, когда двоеточие (:) не используется

public class TestRegEx 
{ 
    private static readonly Regex KeyValFileRegex = new Regex(@"\b(?<key>(?!:)[\w\.]+|[ \w\.]+)\s*[\s=:]\s*(?<value>[^\n]*)(?=[^()\n]*[ =:\(]?)", RegexOptions.IgnoreCase); 
    private static int Main(string[] args) 
    { 
     string inputStr = @"// This is a comment 
    // NotUsed : 123654 

**************************************** 
*   DESCRIPTION 
*************************************** 
Header:   xxx 
Date:   20010101  
ReqDate:20150402 
P.O.   123456 
Qty   10000 
Part Number:  xx-yy-456 
Type:   J 
Product:   xxyy123456V0.01 (bulk) 
Cust ID: 51 
Model:   
Location:  60 
UPC:   123456 
* 
cust_ref:  Hello Worlkd 
* 
*************************************** 
*   Data 
***************************************"; 

     var stream = new MemoryStream(Encoding.UTF8.GetBytes(inputStr)); 

     using (var r = new StreamReader(stream)) 
     { 
      var data = new Data(); 
      string line; 
      while ((line = r.ReadLine()) != null) 
      { 
       var match = KeyValFileRegex.Match(line); 

       if (!match.Success) continue; 

       var key = match.Groups["key"].Value; 
       var value = match.Groups["value"].Value; 

       if (!string.IsNullOrEmpty(value)) value = value.Trim(); 

       switch (key) 
       { 
        case "Header": 
         data.Header = value; 
         break; 
        case "ReqDate": 
         data.RequestedDeliveryDate = value; 
         break; 
        case "Qty": 
         data.Qty = Convert.ToInt32(value); 
         break; 
        case "Type": 
         data.Type = value; 
         break; 
       } 
      } 
     } 

     return 0; 
    } 

    private class Data 
    { 
     public string Header { set; get; } 
     public string RequestedDeliveryDate { set; get; } 
     public string Brand { set; get; } 
     public string Po { set; get; } 
     public int Qty { set; get; } 
     public string Type { set; get; } 
    } 
} 

Любая помощь будет очень признательна.

+0

так что если двоеточия нет, что бы вы использовали для определения разных полей? – Jeremy

+2

Вы считали, что просто пишете код, чтобы разобрать это? Для каждой строки проверяйте пробелы '//' и '*' или пустые строки. Все остальное ищет двоеточие, которое нужно разбить, или если на первом месте нет двоеточия. Если пробел не пропускается. – juharr

ответ

0

Ваше текущее регулярное выражение является ошибочным, поле «Cust ID» возвращается с «Cust» в качестве ключа, а остальная часть - как значение. Причиной этого является часть регулярного выражения [\s=:]. Он настроен на использование символа пробела и двоеточия в качестве разделителя.

Таким образом, даже при наличии текущего набора разделителей у вас есть проблема. Теперь вы можете поместить что-нибудь еще в эти скобки, но чем больше разделителей вы добавите к нему, тем больше проблем у вас будет. Кажется, вы не знаете, какой формат данных ожидать.

Как правило, вы должны настроить регулярное выражение, чтобы принять либо один из разделителей, а не попробовать все из них в том же скрипте. Это делается путем попытки разобрать один скрипт, и если результаты не заданы, попробуйте другой скрипт. Конечно, это плохая практика, но если вы работаете с непредсказуемыми данными, это самый простой подход.

0

Вы можете попробовать другой подход: если есть двоеточие, соответствует любому количеству пробелов, а если нет, сопоставьте не менее 3 пробелов - и используйте это совпадение для разделения строки. Посмотрите:

public int Start() 
{ 
    var rxDelim = new Regex(@"(?(:):\s*|\s{3,})\s*"); 
    var inputStr = @"// This is a comment 
       // NotUsed : 123654 

**************************************** 
*   DESCRIPTION 
*************************************** 
Header:   xxx 
Date:   20010101  
ReqDate:20150402 
P.O.   123456 
Qty   10000 
Part Number:  xx-yy-456 
Type:   J 
Product:   xxyy123456V0.01 (bulk) 
Cust ID: 51 
Model:   
Location:  60 
UPC:   123456 
* 
cust_ref:  Hello Worlkd 
* 
*************************************** 
*   Data 
***************************************"; 

var stream = new MemoryStream(Encoding.UTF8.GetBytes(inputStr)); 
var line = string.Empty; 
using (var r = new StreamReader(stream)) 
{ 
    var data = new Data(); 
    var s = string.Empty; 
    while ((s = r.ReadLine()) != null) 
    { 
     if (Regex.IsMatch(s, @"(?i)^\*[^\r\n]*Description")) 
     { 
      s = r.ReadLine() + "\r\n"; 
      line += s; 
      var add = r.ReadLine() + "\r\n"; 
      while (add != null && !Regex.IsMatch(add, @"(?i)^\*[^\r\n]*Description")) 
      { 
       line += add + "\r\n"; 
       add = r.ReadLine(); 
      } 
      var matches = line.Split(new[] { "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries).Select(p => rxDelim.Split(p).GetLength(0) > 1 && rxDelim.Split(p)[0] != "*" && !rxDelim.Split(p)[0].TrimStart(new[] { ' ' }).StartsWith("//") ? 
        new { Key = rxDelim.Split(p)[0], Value = rxDelim.Split(p)[1] } : 
        new { Key = string.Empty, Value = string.Empty }); 
      foreach (var v in matches) 
      { 
       if (!String.IsNullOrWhiteSpace(v.Key) && !String.IsNullOrWhiteSpace(v.Value)) 
       { 
        switch (v.Key) 
        { 
         case "Header": 
          data.Header = v.Value; 
          break; 
         case "ReqDate": 
          data.RequestedDeliveryDate = v.Value; 
          break; 
         case "Qty": 
          data.Qty = Convert.ToInt32(v.Value); 
          break; 
         case "Type": 
          data.Type = v.Value; 
          break; 
        } 
       } 
      } 
     } 
    } 
} 
return 0; 
} 
+0

Ваш ответ делает трюк с небольшим модификатором: используемые вами индексы ([1] и [2]) не являются группой захвата, вы должны использовать ([2] и [3]) и выполнять проверку длины split (размер> 2). –

+0

Я только что запустил ваш код как есть, и все ключи на Dict являются пустыми строками, я предполагаю, что первое совпадение пусто от каждого удара. Я проверю его снова .. thx –

+0

Я думаю, что, наконец, понял. Вы можете читать строки за строкой, получить раздел «Описание», затем анализировать с помощью регулярного выражения и заполнять необходимые поля объекта данных. Вы можете добавить дополнительную поддержку на местах для удовлетворения ваших требований. –

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