【问题标题】:How to search a string for values and convert values如何在字符串中搜索值并转换值
【发布时间】:2019-10-16 05:10:07
【问题描述】:

我有一个 API 接受在进入服务器之前需要正确格式化的字符串。

进入服务器的格式如下

"{Country ABR} {Day/Hour} {State ABR} {Title} {hrs.} ({Month Year}.)"

客户可能发送的几种可能性:

"US Construction 7/70 hrs."

"IA Private hrs US.

"OIL US 8/70 hrs (Dec 2014).

转换用户输入后的几个有效示例是:

"US 7/70 MI Construction hrs."

"US IA Private hrs."

"US OIL 8/70 hrs. (Dec 2014)" 

转换器将输入排列成正确的顺序。 hrs 总是以句点结尾并在句子外重新排列 ({Month Year}),如图所示。

目前为止

       [TestMethod]
    public void TestMethod1()
    {
        var toConvert = "USA Construction 70/700 (Dec 2014) hrs";
        var converted = ConvertHOSRules(toConvert);

        Assert.AreEqual(converted, "USA 70/700 Construction hrs.(Dec 2014)");
    }

    private string ConvertHOSRules(string input)
    {
        //todo refactor
        string output = "";

        string country = Regex.Match(input, @"\b(USA|CAN|MEX)\b").Value +" ";
        string dateHours =  Regex.Match(input,@"\d{1,2}\/\d{1,3}").Value + " ";
        string hrs = Regex.Match(input, @"\b(hrs)\b").Value ;
        var date = Regex.Match(input, @"\(([a-zA-Z]+\s{1}[0-9]{4})\)").Value + " ";
        string title = input.Replace(country, "").Replace(date, "").Replace(dateHours, "").Replace(hrs, "");
        output = $"{country} {dateHours} {title} {hrs}.{date}";
        return output;

    }

这是传递我需要重构.. +“”就像懒惰程序员的空守卫

【问题讨论】:

  • 用这些例子做测试。然后尝试编写正则表达式以通过测试。
  • 这听起来是一个非常具有挑战性的问题,主要是因为看起来用户正在输入纯文本。这意味着他们不知道您解析文本的规则,因此您不能期望他们以一致的方式输入任何内容。那么任何州或国家的缩写也可以是标题的一部分。还有很多其他人不会想到的事情。您能否更改 API 以使数据已被分成多个字段?
  • 有关于示例的文档,因此客户可能发送的可能性是我正在考虑的唯一值。如果距离不远,那么我将发送一个错误的请求,其中包含一个错误代码,说明文本无效,请参阅文档以获取帮助
  • 匹配项还会报告它们的位置。尝试匹配您知道其格式的所有子部分。对原始字符串使用区间算术,减去匹配的子部分。然后,删除任何仅由空格组成的不匹配区间。之后,最多应该有一个间隔。这是你的头衔。
  • @NicoSchertler 我在做什么我只是对(2014 年 12 月)有疑问。有什么建议吗?

标签: c# regex algorithm regex-group regex-alternation


【解决方案1】:

这个问题很有趣,特别是如果我们想为它设计算法,因为我猜我们的正则表达式是不必要的。


如果我们希望使用表达式来做到这一点,我会从一个简单的表达式开始,例如在两个捕获组中列出可能的国家和州:

(US|UK|FR)
(CA|WA|IA|MO|MI)

那么我们的时间安排得很好:

(\d+\/\d+)

月份(.+?) 和年份([0-9]+) 也是如此:

\(((.+?)\s+([0-9]+))\)

这是我们在使用其他关键字时遇到问题的地方,例如 ConstructionOIL,我们可以添加最少 3 个字符,以免与州和国家/地区发生冲突:

([A-Z][a-z]{2,}|[A-Z]{3,})

最后我们将通过收集所有剩余的空格和其他字符来清理我们的字符串,例如 hrs. 这只是重复,我们可能不想匹配或捕获它。

(.*?)

最后,我们将使用交替组合:

(US|UK|FR)|(CA|NY|IA|TX|MI)|(\d+\/\d+)|\(((.+?)\s+([0-9]+))\)|([A-Z][a-z]{2,}|[A-Z]{3,})|(.*?)

DEMO

测试

using System;
using System.Text.RegularExpressions;

public class Example
{
    public static void Main()
    {
        string pattern = @"(US|UK|FR)|(CA|NY|IA|TX|MI)|(\d+\/\d+)|\(((.+?)\s+([0-9]+))\)|([A-Z][a-z]{2,}|[A-Z]{3,})|(.*?)";
        string input = @"US 7/70 MI Construction hrs.
US IA Private hrs.
US OIL 8/70 hrs. (Dec 2014)
UK 7/70 MI Construction hrs.
UK IA Private hrs.
UK OIL 8/70 hrs. (Dec 2014)
FR 7/70 MI Construction hrs.
FR IA Private hrs.
FR OIL 8/70 hrs. (Dec 2014)";
        RegexOptions options = RegexOptions.Multiline;

        foreach (Match m in Regex.Matches(input, pattern, options))
        {
            Console.WriteLine("'{0}' found at index {1}.", m.Value, m.Index);
        }
    }
}

DEMO

正则表达式

如果不需要此表达式,可以在 regex101.com 中修改/更改。

正则表达式电路

jex.im 可视化正则表达式:

【讨论】:

  • 这很有趣且有用.. 感谢您的回复
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-30
  • 1970-01-01
  • 2014-07-26
相关资源
最近更新 更多