【问题标题】:Regex that matches anything before a certain character?正则表达式匹配某个字符之前的任何内容?
【发布时间】:2009-06-03 16:42:01
【问题描述】:

我必须从文本中解析一堆统计数据,它们都被格式化为数字。

比如这一段:

纽约 81.8% 的人 城市 3 至 8 年级的学生是 达到或超过年级数学水平 标准,相比之下,88.9% 该州其他地区的学生。

我只想匹配 81 和 88 数字,而不是后面的“.8”和“.9”。

我该怎么做?我听说过反向引用或前瞻之类的术语。这些会有帮助吗?

我正在使用 C#。

编辑: 在上面的例子中,我需要得到“3”和“8”。这只是一个简单的例子,但我需要几乎所有的数字。

【问题讨论】:

  • 小数点后的数字在大量人口中具有统计学意义。我会使用短语“百分比”来查找相对数字。
  • 克雷格 - 我不明白你的意思 - 我只是用这个作为例子 - 我的真实数字不是百分比。我只需要去掉“。”之后的字符。和其他模式,如“e+”。这只是一个非常简单的例子。

标签: c# regex parsing lookahead


【解决方案1】:
/[^.](\d+)[^.]/

如下所述,只需使用 MatchObj.Groups(1) 来获取数字。

【讨论】:

  • 那不也能抓取小数点后面的数字吗?可能想在前面放一个 [^.]。
【解决方案2】:

如果你不想处理组,你可以像你说的那样使用前瞻;此模式查找字符串中所有十进制数的整数部分:

Regex integers = new Regex(@"\d+(?=\.\d)");
MatchCollection matches = integers.Matches(str);

matches 将包含8188。如果您想匹配任何数字(无论是否为十进制)的整数部分,您可以改为搜索不以 . 开头的整数:

Regex integers = new Regex(@"(?<!\.)\d+");

这一次,匹配项将包含813888

【讨论】:

  • 在你的第一个正则表达式中,你应该把\d+放在最后的结束括号之前,这样你就不会在句子的结尾出现误报。
  • 好点。我选择了\d,因为我不在乎有多少。谢谢指正。
  • 在你的第二个代码块中,那是什么样的语法?不知道是什么?
  • (?\. 的匹配
  • 链接以获得更深入的信息:regular-expressions.info/lookaround.html#lookbehind
【解决方案3】:

完整的 C# 解决方案:

/// <summary>
/// Use of named backrefence 'roundedDigit' and word boundary '\b' for ease of
/// understanding
/// Adds the rounded percents to the roundedPercents list
/// Will work for any percent value
/// Will work for any number of percent values in the string
/// Will also give those numbers that are not in percentage (decimal) format
/// </summary>
/// <returns>true if success, false otherwise</returns>
public static bool TryGetRoundedPercents(string digitSequence, out List<string> roundedPercents)
{
    roundedPercents = null;
    string pattern = @"(?<roundedDigit>\b\d{1,3})(\.\d{1,2}){0,1}\b";

    if (Regex.IsMatch(digitSequence, pattern))
    {
        roundedPercents = new List<string>();
        Regex r = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.ExplicitCapture);

        for (Match m = r.Match(digitSequence); m.Success; m = m.NextMatch())
            roundedPercents.Add(m.Groups["roundedDigit"].Value);

        return true;
    }
    else
        return false;
}

从您的示例返回 81、3、8 和 88

【讨论】:

    【解决方案4】:
    [^.](\d+)
    

    根据您的示例,这将匹配“81”、“3”、“8”、“88”

    在获得号码之前,您会获得一个额外的字符,但您可以在代码中将其删除。

    【讨论】:

      【解决方案5】:

      试试:

      [0-9]*(?=[3])
      

      它使用前瞻来仅匹配后跟小数点的数字。

      C#代码:

      Regex regex = new Regex("[0-9]+(?=[.])");
      MatchCollection matches = regex.Matches(input);
      

      【讨论】:

      • 您将在每个句点获得一个空白条目,因为您匹配 0 位或更多位而不是 1 位或更多位。
      • 谢谢,之前很着急,没注意
      【解决方案6】:
      /(\d+)\.\d/g
      

      这将匹配任何后面有小数的数字(我认为这是你想要的),但只会捕获小数之前的数字。 \d 只会捕获数字(与 [0-9] 相同),因此它非常简单。

      编辑:如果你想要三个和八个,你甚至不需要检查小数。

      Edit2:抱歉,已修复它,所以它会忽略所有小数位。

      /(\d+)(?:\.\d+)?/g
      

      【讨论】:

      • 请查看我的编辑 - 我需要获取所有数字,但要去掉小数点后的数字(我的实际数据具有疯狂的精度)
      • 如果我使用你的第二个,我会得到 9 和 1,这是我不想要的。
      【解决方案7】:

      尝试使用 /(\d+)((\.\d+)?)/

      这基本上意味着将一个数字序列和一个可选的小数点与另一个数字序列匹配。然后,使用MatchObj.Groups(1) 作为第一个匹配值,忽略第二个。

      【讨论】:

        【解决方案8】:

        这不是您询问的语言,但它可以帮助您思考问题。

        $ echo "A total of 81.8 percent of New York City students in grades 3 to 8 are meeting or exceeding grade-level math standards, compared to 88.9 percent of students in the rest of the State." \
        | fmt -w 1 | sed -n -e '/^[0-9]/p' | sed -e 's,[^0-9].*,,' | fmt -w 72
        81 3 8 88
        

        第一个 fmt 命令要求以下命令分别考虑每个单词。 “sed -n”命令只输出至少以一个数字开头的单词。第二个 sed 命令删除单词中的第一个非数字字符,以及之后的所有内容。第二个 fmt 命令将所有内容重新组合成一行。

        $ echo "This tests notation like 6.022e+23 and 10e100 and 1e+100." \
        | fmt -w 1 | sed -n -e '/^[0-9]/p' | sed -e 's,[^0-9].*,,' | fmt -w 72
        6 10 1
        

        【讨论】:

          猜你喜欢
          • 2022-07-06
          • 2016-10-22
          • 1970-01-01
          • 2021-09-30
          • 1970-01-01
          • 1970-01-01
          • 2016-05-05
          • 1970-01-01
          • 2021-01-05
          相关资源
          最近更新 更多