如何从有条件的复杂字符串内容中捕获特定数据?

时间:2019-02-01 13:13:10

标签: c#

我有一个内存映射文件,其中保存着股市数据。我正在存储如下数据: Symbol, Date, Open, High, Close, Low, Volume AAPL,25/01/2019 03:00:00,153.55,153.9,153.9,153.55,821 AAPL,25/01/2019 03:02:00,154.2,154.21,154.21,154.2,966

现在,我们要获取每行的收盘价清单。确实我们需要这样,如果当前时间戳是25/01/2019 11:35:00 AM并且条件是15滴答,那么我需要从25/01/2019 11:19:00 AM到11:34的收盘价清单:凌晨00点。

我正在尝试使用子字符串和拆分来收盘价,但是我有超过10,000条记录,所以这会很奇怪。

string name = "AAPL,25/01/2019 03:00:00,153.55,153.9,153.9,153.55,821";
//name = name.Substring(name.IndexOf(',') + 1);
//name = name.Split(',').Last();


1 个答案:

答案 0 :(得分:1)

您必须将任务分为两部分。首先读取文件并将其转换为适当的结构。为此,您必须创建一个代表一个股票数据记录的类:

public class StockData
{
    public string Symbol { get; set; }
    public DateTime Date { get; set; }
    public decimal Open { get; set; }
    public decimal High { get; set; }
    public decimal Close { get; set; }
    public decimal Low { get; set; }
    public int Volume { get; set; }
}

然后创建一个读取数据的方法

private static IEnumerable<StockData> ReadStockData(string path)
{
    const int ExpectedSize = 15000;

    var stockData = new List<StockData>(ExpectedSize); // For efficiency. Defines starting size
                                                       // of internal buffer and avoids
                                                       // resizing operations.
    foreach (string line in File.ReadLines(path)) {
        string[] parts = line.Split(',');
        if (parts.Length == 7) { // Exclude empty lines etc.
            var data = new StockData {
                Symbol = parts[0],
                Date = DateTime.Parse(parts[1]),
                Open = Decimal.Parse(parts[2]),
                High = Decimal.Parse(parts[3]),
                Close = Decimal.Parse(parts[4]),
                Low = Decimal.Parse(parts[5]),
                Volume = Int32.Parse(parts[6])
            };
            stockData.Add(data);
        }
    }
    return stockData;
}

为简单起见,我未包含任何错误处理。您可能要使用TryParse而不是Parse等。但这取决于数据的质量。

然后您可以选择和分析数据

var data = ReadStockData(path);
var start = new DateTime(2019, 1, 25, 3, 0, 0);
var end = start.AddMinutes(15);
var result = data
    .SkipWhile(d => d.Date < start)
    .TakeWhile(d => d.Date <= end);
foreach (StockData sd in result) {
    // ...
}

您还可以完全避免将库存数据缓存在列表中,而使用Iterator

private static IEnumerable<StockData> ReadStockData(string path)
{
    foreach (string line in File.ReadLines(path)) {
        string[] parts = line.Split(',');
        if (parts.Length == 7) { // Exclude empty lines etc.
            var data = new StockData {
                Symbol = parts[0],
                Date = DateTime.Parse(parts[1]),
                Open = Decimal.Parse(parts[2]),
                High = Decimal.Parse(parts[3]),
                Close = Decimal.Parse(parts[4]),
                Low = Decimal.Parse(parts[5]),
                Volume = Int32.Parse(parts[6])
            };
            yield return data;
        }
    }
}

优点是在消耗文件的同时读取文件。一旦TakeWhile返回最后一个所需的记录,它也会停止读取和转换文件。但是,如果您打算对同一数据运行多个查询,则将其存储在列表中仍然有意义。使用迭代器方法,您仍然可以使用

var result = data
    .SkipWhile(d => d.Date < start)
    .TakeWhile(d => d.Date <= end)
    .ToList();