如何更可靠、更快速地从 C# 中的文本 table 字符串中获取数据

How to get data from text table string in C# more reliably and quickly

我正在将一些数据从 SAP GUI 屏幕复制到剪贴板。当我将它粘贴到记事本或任何文本编辑器时,它看起来像下面。

我只想要来自剪贴板文本 table 字符串的 3 个字段 [Created by, PO date, Document]。

目前我正在设法读取如下数据。

public class DocData
{
    public string CreatedBy { get; set; }
    public string PODate { get; set; }
    public string Document { get; set; }
}

private void GetDocumentData()
{
  var clipboardData = Clipboard.GetText(TextDataFormat.Text);
  List<DocData> docDataList = new List<DocData>();
  for (int separatorCounter = 20; separatorCounter < clipboardData.Count(); separatorCounter = separatorCounter + 13)
  {
   DocData docData = new DocData();
   int index = GetNthIndex(clipboardData, '|', separatorCounter);
   if (index != -1)
   {
    var dataString = clipboardData.Substring(index + 1);
    var sepIndex = dataString.IndexOf('|');
    if (sepIndex != -1)
    {
     docData.CreatedBy = dataString.Substring(0, sepIndex).Trim();
    }
   }
   index = GetNthIndex(clipboardData, '|', separatorCounter + 2);
   if (index != -1)
   {
    var dataString = clipboardData.Substring(index + 1);
    var sepIndex = dataString.IndexOf('|');
    if (sepIndex != -1)
    {
     docData.PODate = dataString.Substring(0, sepIndex).Trim();
    }
   }
   index = GetNthIndex(clipboardData, '|', separatorCounter + 4);
   if (index != -1)
   {
    var dataString = clipboardData.Substring(index + 1);
    var sepIndex = dataString.IndexOf('|');
    if (sepIndex != -1)
    {
     docData.Document = dataString.Substring(0, sepIndex).Trim();
    }
   }
   if (!string.IsNullOrEmpty(docData.Document))
   {
    docDataList.Add(docData);
   }
  }
 }

任何人都可以提出更好的方法来做到这一点而不会过多地操纵字符串。

这是解决您的问题的一种方法。此示例首先按行拆分文本,然后使用 header 查找所需数据的位置,然后遍历行并获取数据。

尚未测试(如果您粘贴文本而不是该屏幕截图,我可以测试 :)),但它应该可以工作。查看代码中的注释以进行解释。

如果您还有其他问题,请随时提出。

编辑:添加了缺失的方法

//result list
List<DocData> docDataList = new List<DocData>();

//get clipboard data
string clipboardData = Clipboard.GetText(TextDataFormat.Text);

//split it to array of lines using Environment.NewLine (\r\n);
string[] reportLines = clipboardData.Split(new[] { Environment.NewLine }, StringSplitOptions.None);

if (reportLines.Length < 4) //just an example of checking if there's enough lines
    throw new Exception("wrong number of lines");

//get correct indexes by reading header (positioned on third line, index 2) - in case order changes
int createdIndex = GetColumnIndex(reportLines[2], "Created by");
int PODateIndex = GetColumnIndex(reportLines[2], "PO Date");
int documentIndex = GetColumnIndex(reportLines[2], "Document");

//when you have indexes, loop through remaining lines, starting at fifth (index 4) and get data from that "columns"
for (int i = 4; i<reportLines.Length; i++)
{
    //now split current line by pipes
    string[] lineData = reportLines[i].Split('|');
    //create instance of your class and add data from specific indexes
    DocData docData = new DocData()
    {
        CreatedBy = lineData[createdIndex].Trim(), //also, trim ending spaces,
        PODate = lineData[PODateIndex].Trim(),
        Document = lineData[documentIndex].Trim()
    };
    docDataList.Add(docData);
}

public int GetColumnIndex(string headerLine, string columnName)
{
    List<string> headerNames = headerLine.Split('|').ToList(); //split header columns using pipe |.

    //get index of column by trimming and searching throught header column names
    return headerNames.IndexOf(headerNames.FirstOrDefault(h => h.Trim().Equals(columnName, StringComparison.InvariantCultureIgnoreCase)));

}