【问题标题】:C# Regular Expressions - Get Second Number, not FirstC# 正则表达式 - 获取第二个数字,而不是第一个
【发布时间】:2015-07-16 15:06:12
【问题描述】:

我有以下 HTML 代码:

<td class="actual">106.2% </td> 

我通过两个阶段获得数字:

Regex.Matches(html, "<td class=\"actual\">\\s*(.*?)\\s*</td>", RegexOptions.Singleline);
Regex.Match(m.Groups[1].Value, @"-?\d+.\d+").Value

上面的代码行给了我想要的,106.2

问题是有时 HTML 可能会有点不同,像这样:

<td class="actual"><span class="revised worse" title="Revised From 107.2%">106.4%</span></td>

在最后一种情况下,我只能得到 107.2,我想得到 106.4 是否有一些正则表达式技巧可以说,我想要句子中的第二个数字而不是第一个?

【问题讨论】:

  • 问题是有时 HTML 可能会有点不同 是关键短语。您是否考虑过使用 HTML 解析器?
  • 快速方法:获取所有匹配项并获取最后一个。更好的方法:解析 HTML。
  • 用正则表达式解析HTML可以有unfortunate consequences。改用 HTML 解析器;一旦你有正确的文本节点,然后在那个文本上使用正则表达式。
  • 感谢您的快速反馈!我正在尝试使用正则表达式进行最后一次拍摄。如果它不能按我的意愿工作,我会尝试一个 Html 解析器。

标签: c# regex


【解决方案1】:

如果您的 HTML 代码来自不同的提供商,或者您当前的 CMS 有多个使用不同 HTML 格式样式的 CMS,则依赖正则表达式是不安全的。

我建议一个基于 HtmlAgilityPack 的解决方案:

public string getCleanHtml(string html)
{
    var doc = new HtmlAgilityPack.HtmlDocument();
    doc.LoadHtml(html);
    return HtmlAgilityPack.HtmlEntity.DeEntitize(doc.DocumentNode.InnerText);
}

然后:

var txt = "<td class=\"actual\">106.2% </td>";
var clean = getCleanHtml(txt);
txt = "<td class=\"actual\"><span class=\"revised worse\" title=\"Revised From 107.2%\">106.4%</span></td>";
clean = getCleanHtml(txt);

结果: 和

您不必担心内部的格式化标签和任何 XML/HTML 实体引用。

如果您的文本是纯 HTML 字符串的子字符串,那么您可以使用正则表达式或任何其他字符串操作方法。

更新:

您似乎需要来自&lt;td&gt; 标签的节点值。这是一个方便的方法:

private List<string> GetTextFromHtmlTag(string html, string tag)
{
   var result = new List<string>();
   HtmlAgilityPack.HtmlDocument hap;
   Uri uriResult;
   if (Uri.TryCreate(html, UriKind.Absolute, out uriResult) && uriResult.Scheme == Uri.UriSchemeHttp)
   { // html is a URL 
       var doc = new HtmlAgilityPack.HtmlWeb();
       hap = doc.Load(uriResult.AbsoluteUri);
   }
   else
   { // html is a string
       hap = new HtmlAgilityPack.HtmlDocument();
       hap.LoadHtml(html);
   }
   var nodes = hap.DocumentNode.ChildNodes.Where(p => p.Name.ToLower() == tag.ToLower() && p.GetAttributeValue("class", string.Empty) == "previous"); // SelectNodes("//"+tag);
    if (nodes != null)
        foreach (var node in nodes)
           result.Add(HtmlAgilityPack.HtmlEntity.DeEntitize(node.InnerText));
    return result;
}

你可以这样称呼它:

var html = "<td class=\"previous\"><span class=\"revised worse\" title=\"Revised From 1.3\">0.9</span></td>\n<td class=\"previous\"><span class=\"revised worse\" title=\"Revised From 107.2%\">106.4%</span></td>";
var res = GetTextFromHtmlTag(html, "td");

如果只需要获取特定的标签,

如果您的文本中包含数字,而您只需要数字,则可以使用正则表达式:

var rx = new Regex(@"[+-]?\d*\.?\d+"); // Matches "-1.23", "+5", ".677"

见demo

【讨论】:

  • 我过去曾使用过这个 HtmlAgilityPack,但它需要更多的代码才能做到这一点。实际上,我正在尝试仅使用正则表达式来获取信息,如果不能,我将使用您的建议并使用此 HTML 解析器。
  • 这不仅仅是关于文本中的数字,因为还有其他数字,这是关于收集正确的数字:) 无论如何,感谢您提供的信息。
  • 当然,当从一个简单的字符串中获取正确的数字时,正则表达式是强制性的,但是当它是 HTML 时,使用解析器会更安全,它会首先为您提供正确的标记文本,而无需很痛苦。我希望有一天你会回到这篇文章。
【解决方案2】:

试试 XML 方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;


namespace ConsoleApplication34
{
    class Program
    {

        static void Main(string[] args)
        {
            string input = "<td class=\"actual\"><span class=\"revised worse\" title=\"Revised From 107.2%\">106.4%</span></td>";

            XElement element = XElement.Parse(input);

            string value = element.Descendants("span").Select(x => (string)x).FirstOrDefault();

        }

    }

}

【讨论】:

  • 这在这种情况下可能有效,但如果输入不是 XML 有效的,则会失败。
  • 同意,但是当发布数量有限的示例数据时,您永远不知道用户真正想要做什么。
  • 我仍然认为关键是 HTML 可以有点不同。这意味着我们无法确定输入质量,更不用说 XML 的有效性了。不过,我还是喜欢XElement。
【解决方案3】:

我想分享我为我的问题找到的解决方案。

所以,我可以有如下 HTML 标签:

<td class="previous"><span class="revised worse" title="Revised From 1.3">0.9</span></td>
<td class="previous"><span class="revised worse" title="Revised From 107.2%">106.4%</span></td>

或者更简单:

<td class="previous">51.4</td>

首先,我通过以下代码获取整行代码:

MatchCollection mPrevious = Regex.Matches(html, "<td class=\"previous\">\\s*(.*?)\\s*</td>", RegexOptions.Singleline);

其次,我使用以下代码仅提取数字:

foreach (Match m in mPrevious)
        {


            if (m.Groups[1].Value.Contains("span"))
            {
                string stringtemp = Regex.Match(m.Groups[1].Value, "-?\\d+.\\d+.\">-?\\d+.\\d+|-?\\d+.\\d+\">-?\\d+.\\d+|-?\\d+.\">-?\\d+|-?\\d+\">-?\\d+").Value;
                int indextemp = stringtemp.IndexOf(">");
                if (indextemp <= 0) break;
                lPrevious.Add(stringtemp.Remove(0, indextemp + 1));
            }
            else lPrevious.Add(Regex.Match(m.Groups[1].Value, @"-?\d+.\d+|-?\d+").Value);
        }

首先我开始识别是否有 SPAN 标签,如果有,我将这两个数字放在一起,并考虑了正则表达式的不同可能性。确定要删除不重要信息的角色,并删除我不想要的内容。

效果很好。

感谢大家的支持和快速解答。

【讨论】:

  • 请考虑支持那些被证明有帮助的答案,并接受对您有用的答案。请注意,从 HTML 标记文档中获取特定值时,不建议使用正则表达式。我已经用一种从td 和 HTML 文档中的其他标签中提取干净文本的特定方法更新了我的答案。
  • @stribizhev 我对他们都投了赞成票,因为他们都非常有帮助!我没有将任何定义为正确答案,因为它们都没有单独解决我需要的问题。也许Sky Fang的解决方案,但我没有测试他的新解决方案,我使用了我的。
  • 当然,您也可以接受您的回答,您自己解决问题真是太好了。继续加油!
  • @stribizhev 我不是一个人解决的!感谢您和其他回复者,我解决了它!没有你和其他人,我会花更多的时间。
【解决方案4】:
string html = @"<td class=""actual""><span class=""revised worse"" title=""Revised From 107.2%"">106.4%</span></td>
<td class=""actual"">106.2% </td>";
string patten = @"<td\s+class=""actual"">.*(?<=>)(.+?)(?=</).*?</td>";
foreach (Match match in Regex.Matches(html, patten))
{
    Console.WriteLine(match.Groups[1].Value);
}

我已按照您的意愿更改了正则表达式,输出为

106.4%
106.2%

【讨论】:

  • 只有当数字最后有 % 时,您的正则表达式才有效。但如果他们什么都没有呢?或者,如果他们有任何其他事情。您能否为此调整正则表达式?提前致谢。
猜你喜欢
  • 2011-03-29
  • 2014-11-07
  • 2022-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多