在满足条件之前查找值
Posted
技术标签:
【中文标题】在满足条件之前查找值【英文标题】:Finding a value before a condition is met 【发布时间】:2019-11-11 07:45:42 【问题描述】:有什么办法可以简化下面的代码,让它看起来更清晰、更优雅?
以下代码使用 Linq 和正则表达式返回在文本集合中找到的值集合:
IEnumerable<double> _results = pages.Select(result =>
Regex _regex = new Regex("<my regex here>", RegexOptions.None);
MatchCollection _matches = _regex.Matches(result);
double _number = 0.0;
foreach (Match _match in _matches)
if (_match.Groups["value"].Value.Contains("("))
break;
else
double.TryParse(_match.Groups["value"].Value, out _number);
return _number;
);
如您所见,正则表达式很棘手,它基本上返回在满足条件之前在每个文本中找到的最后一个值,这就是预期的结果。
您如何简化前面的代码以寻求优雅?内存和 CPU 利用率不是问题。
【问题讨论】:
为什么不对你的正则表达式进行编码,这样它就不会选择带有括号的匹配项,或者使用括号的存在来确定哪个第一个先验值作为匹配集合值返回?这个问题将受益于您的原始数据样本,其中突出显示您想要从中提取哪些数据 @CaiusJard 相信我,你不想看到原始数据,它比 html 更糟糕,它基本上是服务器生成的非常神秘的日志。但是该算法仍然非常有效:正则表达式在满足条件之前找到的最后一个数字。 如果我不想看,我就不会问了 ;) 如果你坚持:) ...这是一个块:reactid="17"/>2,941.7616.84(12.7) 【参考方案1】:如果我正确理解您的代码,我会这样做,此语法在 C#7.0 中有效,内联 out
变量声明:
Regex _regex = new Regex("<my regex here>", RegexOptions.None);
IEnumerable<double> _results = pages.Select(_regex.Matches)
.Where(match => !match.Groups["Value"].Value.Contains("("))
.Select(match => double.TryParse(match.Groups["Value"].Value, out double number) ? number : number);
【讨论】:
请注意,在找到括号之前匹配可能不止一个,在这种情况下,我需要最后一个。您的代码似乎返回了条件之前找到的所有项目,而我只需要最后一个。 我喜欢这个想法,我目前正在改进它,因为它也不能编译......但我知道你来自哪里。 感谢您向我展示了一条可以遵循的路径,我已根据您的建议使用最终代码添加了此问题的答案。【参考方案2】:尽管bobince's advice 关于正则表达式和 HTML :) 这是一个基于正则表达式的解决方案:
.NET 的正则表达式引擎可以倒退,所以我们可以利用这一点,让我们的 rex 在 > .*?):
>(?<v>[,.0-9]+)<.*?\([.0-9]+\)
这是“匹配并命名 >
Regex r = new Regex(">(?<v>[,.0-9]+)<.*?\([.0-9]+\)", RegexOptions.RightToLeft /*other options here*/);
foreach(var p in pages)
Match m = r.Match(p, p.Length - 1);
MessageBox.Show(m.Groups["v"].Value); //finds 16.84
例如:
See it here
【讨论】:
为什么有人会说他的答案没有用?我会尝试@Caius 并使用我真正的正则表达式让你知道。谢谢! 我听从了你的建议,更改了正则表达式,现在它返回一个值,这进一步简化了 Linq 语句。谢谢!【参考方案3】:在@dan-d 的回答之上添加,这可能是最简单易读且更优雅的代码:
double[] _results = _pages
.Select(page => _regex.Matches(page).Cast<Match>().Select(value => value.Groups["value"].Value))
.Select(value => value.TakeWhile(condition => !condition.Contains("(")).Last())
.Select(number => double.TryParse(number, out double _result) ? _result : _result)
.ToArray();
第一个 select 遍历所有数据页并使用正则表达式返回包含所有找到值的数组。第二个 select 查找每个页面的条件之前的最后一个值(该值是否有括号);而最后的 select 评估结果,返回一个双精度数组。
最后,在遵循@caius-jard 的建议后,改进正则表达式现在返回一个值,因此进一步将linq 语句简化为:
double[] _results = _pages
.Select(page => _regex.Matches(page).Cast<Match>().Select(value => value.Groups["value"].Value).First())
.Select(number => double.TryParse(number, out double _result) ? _result : _result)
.ToArray();
【讨论】:
以上是关于在满足条件之前查找值的主要内容,如果未能解决你的问题,请参考以下文章
linq+lambda+delegate,从list中查找到满足匹配条件的所有数据索引值