从文件中检索字符串,当多行包含完全相同的字符串时使用 Linq 进行过滤
Retrieve strings from a file, filtering with Linq when multiple lines contain the exact same string
我将 Visual Studio 与 NuGet 包 MoreLinq 一起用于我的以下解决方案。
我要检索的文件内容示例,该文件还包含其他不相关的数据:
...
#define HELLO
#include "hello.h"
code
#define BYE
#include "hello.h"
...
我对解决方案的尝试,它几乎完全符合我的要求。但差不多,我明白为什么,这是合乎逻辑的:
var files = from file in Directory.EnumerateFiles(path, ".", SearchOption.AllDirectories).Where(s => s.EndsWith(".c") || s.EndsWith(".h"))
from line in File.ReadLines(file)
.SkipWhile(l => l.TrimStart() != ("#define HELLO"))
.TakeUntil(l => l.TrimStart() == ("#define BYE"))
.ToList()
select new
{
File = file,
Line = line
};
foreach (var f in files)
{
sotredLines.Add(f.Line.Trim());
}
此时我的解决方案会给我以下结果:
#define HELLO
#include "hello.h"
code
#define BYE
如果您没有注意到,它缺少我也想检索的最后一行 -> #include "hello.h"。我尝试解决这个问题是在代码中添加以下行
...
.SkipWhile(l => l.TrimStart() != ("#define HELLO"))
.TakeUntil(l => l.TrimStart() == ("#define BYE"))
.TakeUntil(l => l.TrimStart() == ("#include \"hello.h\""))
...
但这(正如预期的那样)仅返回以下结果:
#define HELLO
#include "hello.h"
完全忽略其余想要的信息。因为#include "hello.h"出现了多次,找到第一个就停了
我只想从提到的文件中检索这些行,而不会丢失其中一行:
#define HELLO
#include "hello.h"
code
#define BYE
#include "hello.h"
对于解决方案,同时仍然使用 Linq,请参阅下面的@Freggar 的回答。
您可以在 TakeUntil
中设置一个标志,表明您已超过 #define BYE
:
bool byeFlag = false;
var p = from line in File.ReadLines(file)
.SkipWhile(l => l.TrimStart() != ("#define HELLO"))
.TakeUntil(l =>
{
bool ret = byeFlag;
if (l.TrimStart() == "#define BYE")
{
byeFlag = true;
}
return ret;
})
.ToList()
select new
{
File = file,
Line = line
};
但是正如已经提到的,也许 LINQ 并不是真正适合您尝试做的事情的最佳工具。也许像 ANTLR 这样的解析器更适合这份工作?
我将 Visual Studio 与 NuGet 包 MoreLinq 一起用于我的以下解决方案。
我要检索的文件内容示例,该文件还包含其他不相关的数据:
...
#define HELLO
#include "hello.h"
code
#define BYE
#include "hello.h"
...
我对解决方案的尝试,它几乎完全符合我的要求。但差不多,我明白为什么,这是合乎逻辑的:
var files = from file in Directory.EnumerateFiles(path, ".", SearchOption.AllDirectories).Where(s => s.EndsWith(".c") || s.EndsWith(".h"))
from line in File.ReadLines(file)
.SkipWhile(l => l.TrimStart() != ("#define HELLO"))
.TakeUntil(l => l.TrimStart() == ("#define BYE"))
.ToList()
select new
{
File = file,
Line = line
};
foreach (var f in files)
{
sotredLines.Add(f.Line.Trim());
}
此时我的解决方案会给我以下结果:
#define HELLO
#include "hello.h"
code
#define BYE
如果您没有注意到,它缺少我也想检索的最后一行 -> #include "hello.h"。我尝试解决这个问题是在代码中添加以下行
...
.SkipWhile(l => l.TrimStart() != ("#define HELLO"))
.TakeUntil(l => l.TrimStart() == ("#define BYE"))
.TakeUntil(l => l.TrimStart() == ("#include \"hello.h\""))
...
但这(正如预期的那样)仅返回以下结果:
#define HELLO
#include "hello.h"
完全忽略其余想要的信息。因为#include "hello.h"出现了多次,找到第一个就停了
我只想从提到的文件中检索这些行,而不会丢失其中一行:
#define HELLO
#include "hello.h"
code
#define BYE
#include "hello.h"
对于解决方案,同时仍然使用 Linq,请参阅下面的@Freggar 的回答。
您可以在 TakeUntil
中设置一个标志,表明您已超过 #define BYE
:
bool byeFlag = false;
var p = from line in File.ReadLines(file)
.SkipWhile(l => l.TrimStart() != ("#define HELLO"))
.TakeUntil(l =>
{
bool ret = byeFlag;
if (l.TrimStart() == "#define BYE")
{
byeFlag = true;
}
return ret;
})
.ToList()
select new
{
File = file,
Line = line
};
但是正如已经提到的,也许 LINQ 并不是真正适合您尝试做的事情的最佳工具。也许像 ANTLR 这样的解析器更适合这份工作?