更加“智能”地阅读文本文件

时间:2014-05-27 21:34:42

标签: c# arrays sorting file-io input

我有一个文本文件,其中包含按字母顺序排列的变量列表,其变量编号旁边的格式如下:

aabcdef           208
abcdefghijk       1191
bcdefga           7
cdefgab           12
defgab            100
efgabcd           999
fgabc             86
gabcdef           9
h                 11
ijk               80
...
...

我想将每个文本作为字符串读取并保留其指定的id#,如read“aabcdef”,并将其存储在208的数组中。

我遇到的两个问题是:

  1. 我从未在C#中读过文件,有没有办法阅读,比如说 作为字符串开始行到空白?然后是下一个字符串 一个int直到行尾?

  2. 鉴于这些文件的性质和大小,我不知道每个文件的最高ID值(并非所有数字都被使用,所以有些 文件可以容纳3000这样的数字,但实际上只列出200 变量)那么我怎样才能灵活地存储这些 变量当我不知道数组/列表/堆栈/等等会有多大 需要。

2 个答案:

答案 0 :(得分:5)

基本上你需要Dictionary而不是数组或列表。您可以使用File.ReadLines方法读取所有行,然后根据空格和\ t(制表符)拆分每个行,如下所示:

var values = File.ReadLines("path")
    .Select(line => line.Split(new [] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries))
    .ToDictionary(parts => int.Parse(parts[1]), parts => parts[0]);

然后values[208]会给你aabcdef。它看起来像一个数组不是它:))

另外请确保您没有重复的数字,因为Dictionary键应该是唯一的,否则您将获得例外。

答案 1 :(得分:1)

我一直在考虑如何改进其他答案,并且我发现了基于Regex的替代解决方案,这使得搜索整个字符串(无论是否来自文件)更安全。 / p>

检查您是否可以更改整个正则表达式以包含其他分隔符。示例表达式将检测空格和制表符。

在一天结束时,我发现MatchCollection返回更安全的结果,因为你总是知道第3组是一个整数,第二组是文本,因为正则表达式会为你做很多检查!

StringBuilder builder = new StringBuilder();
builder.AppendLine("djdodjodo\t\t3893983");
builder.AppendLine("dddfddffd\t\t233");
builder.AppendLine("djdodjodo\t\t39838");
builder.AppendLine("djdodjodo\t\t12");
builder.AppendLine("djdodjodo\t\t444");
builder.AppendLine("djdodjodo\t\t5683");
builder.Append("djdodjodo\t\t33");

// Replace this line with calling File.ReadAllText to read a file!
string text = builder.ToString();

MatchCollection matches = Regex.Matches(text, @"([^\s^\t]+)(?:[\s\t])+([0-9]+)", RegexOptions.IgnoreCase | RegexOptions.Multiline);

// Here's the magic: we convert an IEnumerable<Match> into a dictionary!
// Check that using regexps, int.Parse should never fail because
// it matched numbers only!
IDictionary<int, string> lines = matches.Cast<Match>()
                                    .ToDictionary(match => int.Parse(match.Groups[2].Value), match => match.Groups[1].Value);

// Now you can access your lines as follows:
string value = lines[33]; // <-- By value

更新

正如我们在聊天中所讨论的那样,这个解决方案在你向我展示的一些实际用例中并没有起作用,但是这不是什么方法不起作用,而是你的特殊情况,因为键是“[某事]。[某事]”(例如:address.Name)。

我已将正则表达式更改为([\w\.]+)[\s\t]+([0-9]+),因此它涵盖了带有点的键的情况。

这是关于改进匹配正则表达式以满足您的要求! ;)

更新2:

由于您告诉我您需要具有任何字符的键,我已将正则表达式更改为([^\s^\t]+)(?:[\s\t])+([0-9]+)

现在它意味着密钥除了空格和标签之外的任何东西。

更新3:

此外,我看到你陷入了.NET 3.0,并且在.NET 3.5中引入了ToDictionary。如果要在.NET 3.0中使用相同的方法,请将ToDictionary(...)替换为:

Dictionary<int, string> lines = new Dictionary<int, string>();

foreach(Match match in matches)
{
      lines.Add(int.Parse(match.Groups[2].Value), match.Groups[1].Value);
}