0

我有一个像 -

Col.A              Col.B  Col.C  Col.D
--------------------------------------------------------------
* 1  S60-01-GE-44T-AC   SGFM115001195  7520051202   A
  1  S60-PWR-AC         APFM115101302  7520047802   A
  1  S60-PWR-AC         APFM115101245  7520047802   A

或者

 Col.A               Col.B  Col.C  Col.D
--------------------------------------------------------------
* 0  S50-01-GE-48T-AC   DL252040175    7590005605   B
  0  S50-PWR-AC         N/A            N/A          N/A
  0  S50-FAN            N/A            N/A          N/A

对于这些输出,正则表达式 -

(?:\*)?\s+(?<unitno>\d+)\s+\S+-\d+-(?:GE|TE)?-?(?:\d+(?:F|T))-?(?:(?:AC)|V)?\s+(?<serial>\S+)\s+\S+\s+\S+\s+\n

可以很好地捕获 A 列和 B 列。但最近我得到了一种新的输出 -

 Col.A               Col.B  Col.C  Col.D  
---------------------------------------------------------
* 0  S4810-01-64F       HADL120620060  7590009602   A        
  0  S4810-PWR-AC       H6DL120620060  7590008502   A          
  0  S4810-FAN          N/A            N/A          N/A         
  0  S4810-FAN          N/A            N/A          N/A  

如您所见,这些输出中缺少模式“GE|TE”“AC|V” 。如何相应地更改我的正则表达式以保持向后兼容性。

编辑:

您看到的输出是一个完整的字符串,并且由于一些操作限制,我不能在这里使用除正则表达式之外的任何其他概念来获得我想要的值。我知道在这里使用 split 是理想的,但我不能。

4

5 回答 5

2

正则表达式在这里似乎不是正确的方法。使用定位方法

string s = "* 0  S4810-01-64F       HADL120620060  7590009602   A";

bool withStar = s[0] == '*';
string nr = s.Substring(2, 2).Trim();
string colA = s.Substring(5, 18).TrimEnd();
string colB = s.Substring(24, 14).TrimEnd();
...

更新

我想要(或必须)坚持使用正则表达式,测试空格而不是值。当然,这仅在值从不包含空格时才有效。

string[] result = Regex.Split(s, "\s+");

当然,您也可以搜索非空格\S而不是\s.

MatchCollection matches = Regex.Matches(s, "\S+");

或排除星星

(?:\*)?[^*\s]+
于 2012-11-28T17:29:02.430 回答
2

您最好使用 String.Split() 将列值分解为单独的字符串然后处理它们,而不是使用巨大的不可读的正则表达式。

foreach (string line in lines) {
    string[] colunnValues = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
    ...
}
于 2012-11-28T17:29:20.013 回答
1

您的正则表达式甚至不需要GEor TE?之后看到了(?:GE|TE)吗?

这意味着前一个组或符号是可选的。

ACV部分也是如此

于 2012-11-28T17:25:18.390 回答
1

我不会使用正则表达式来解析这些报告。

相反,在去除标题后将它们视为固定列宽报告。

我会做类似的事情(例如,这是冷的,甚至没有测试语法):

   // Leaving off all public/private/error detection stuff
   class ColumnDef  
   {
        string Name { set; get; } 
        int FirstCol { set; get; }
        int LastCol { set; get; }
   }

   ColumnDef[] report = new ColumnDef[] 
   {
         { Name = "ColA",
           FirstCol = 0,
           LastCol = 2
         },
         /// ... and so on for each column
   }

   IDictionary<string, string> ParseDataLine(string line) 
   {
       var dummy = new Dictionary<string, string>();
       foreach (var c in report) 
       {
          dummy[c.Name] = line.Substring(c.FirstCol, c.LastCol).Trim();
       }
   }

这是一个通用 ETL(提取、转换和加载)问题的示例——特别是提取阶段。

在使用 之前,您必须去掉页眉和页脚行ParseDataLine,我不确定是否有足够的信息来执行此操作。根据您的帖子所说,任何空白行或不以空格或 a 开头的*行都是要忽略的页眉/页脚行。

于 2012-11-28T17:33:07.323 回答
1

为什么不尝试这样的事情(?:\*)?\s+(?<unitno>\d+)\s+\S+\s+(?<serial>\S+)\s+\S+\s+\S+(?:\s+)?\n

这是基于您提供的正则表达式构建的,并且由于尾随\n提供的输入将需要以回车结束。

于 2012-11-28T17:55:56.917 回答