正则表达式匹配整数

时间:2014-05-25 14:25:55

标签: c# regex

我输入了以下字符串:

"Monday 11:30am,11 v 2,3 v 4"

我需要替换:

  • 11Hurricanes
  • 2Team abc
  • 3Vipers
  • 4Dodgers
  • 1Frozen Rope

依旧......

但我不想在1中两次替换11

我显然没有掌握正则表达式。但我试过这样的事情:

string text = File.ReadAllText(CSVpath);
text = Regex.Replace(text,
                     string.Format(@"[{0} v]", CurrentCode),
                     string.Format(@"{0} v", TeamName));
text = Regex.Replace(text,
                     string.Format(@"[v {0}]", CurrentCode),
                     string.Format(@"v {0}", TeamName));

根据上面的输入字符串,输出将为:

"Monday 11:30am,Hurricanes v Team abc,Vipers v Dodgers"

5 个答案:

答案 0 :(得分:3)

试试这个正则表达式:

var subject = "Monday 11:30am,11 v 2,3 v 4,5 v 6";
var replaced = Regex.Replace(subject,@"(\d+)\s*v\s*(\d+)","Team$1 with Team$2");

模式分手:

  • (\d+)捕获数字序列并将其保存在group1
  • \s*v\s*检查v个字符包装器的两侧或多个空格。
  • (\d+)捕获数字序列并将其保存在group2

换人:

$1将第一组替换为Team和第一组的匹配。因此,11将替换为Team11,然后将文字withTeam文字与$2相加,并附加group2的匹配。

这是Regex101 demo

答案 1 :(得分:1)

这应该可以解决问题: \d{1,2}(注意最后的空字符!)

答案 2 :(得分:0)

来自http://msdn.microsoft.com/en-us/library/20bw873z(v=vs.110).aspx,似乎与其他语言中的正则表达式语法大致相符,您可以使用" \ d +"匹配一个或多个十进制数字。

我没有为你构建整个正确的正则表达式,因为你的问题只是匹配给定的单一模式(11而不是1)。

答案 3 :(得分:0)

您的初始问题就像是想要输出"Teamnn"的固定格式一样,但您的编辑显着改变了,因此您希望使用团队名称进行替换。

首先要做的是定义从团队编号到团队名称的查找。我在这里完成了一个简单的"平凡" 1 类的数组,但你可能会选择有任何东西来存储它们,如果数字足够大,甚至可能是数据库虽然我怀疑这是不是这样的。重要的是它是一个查找表。

class Team
{
    public string Id { get; set; }
    public string Name { get; set; }
}
static Team[] teams = { 
    new Team { Id = "11", Name = "Hurricanes" },
    new Team { Id = "2",  Name = "Team abc" },
    new Team { Id = "3",  Name = "Vipers" },
    new Team { Id = "4",  Name = "Dodgers" },
    new Team { Id = "1",  Name = "Frozen Rope" },
};

现在定义模式匹配。正则表达式

Regex regex = new Regex(@"(\d+)\s*v\s*(\d+)");

将匹配:

  • (\d+) - 一系列数字,并将其捕获以便以后替换
  • \s* - 可能还有一些空格
  • v - 字母v
  • \s* - 可能还有一些空格
  • (\d+) - 另一个数字序列,并将其捕获以便以后替换

请注意,将捕获两个数字序列 - 团队编号。由于.NET中的正则表达式如何工作,此fixture的整个字符串将被捕获为组0,第一个团队编号将为组1,第二个团队编号将为组2。

public string Test()
{
    string text = "Monday 11:30am,11 v 2,3 v 4";
    foreach (Match match in regex.Matches(text))
    {
        // For the first team in the fixture:
        string team1Id = match.Groups[1].Value; // get the id from the text
        Team team1 = teams.FirstOrDefault(t => t.Id == team1Id); // look it up
        string team1Name = team1.Name; // get the team name
        // For the second team in the fixture:
        string team2Id = match.Groups[2].Value; // get the id from the text
        Team team2 = teams.FirstOrDefault(t => t.Id == team2Id); // look it up
        string team2Name = team2.Name; // get the team name
        // Replace the whole matched string (with numbers)...
        string fixtureWithNumbers = match.Groups[0].Value;
        // ... with the equivalent with team names.
        string fixtureWithNames = team1Name + " v " + team2Name;
        text = text.Replace(fixtureWithNumbers, fixtureWithNames);
    }
    return text;
}

这是写出来的。当然,您可以将其缩小到稍微小一点,如下所示:

public string Test2(string text)
{
    foreach (Match m in Regex.Matches(text, @"(\d+)\s*v\s*(\d+)"))
    {
        text = text.Replace(match.Groups[0].Value,
                            teams.FirstOrDefault(t => t.Id == m.Groups[1].Value)
                                 .Name +
                            " v " +
                            teams.FirstOrDefault(t => t.Id == m.Groups[2].Value)
                                 .Name);
    }
    return text;
}
虽然没有真正的收获,可能以一点可读性或可维护性为代价,但往往被低估的商品。

替代方法是替换foreach循环,并通过RegexMatchEvaluator类中完成循环。 (感谢Dalorzo建议采用这种方法)。为此,我将正则表达式更改为((?<T>\d+)(?=\s*v))|((?<=v\s*)(?<T>\d+))

  • (?<T>\d+) - 一系列数字,并将其捕获为命名项目(T)以便稍后替换
  • (?=\s*v) - 后面跟着一些(或没有)空格和一个字母v
  • | - 或 -
  • (?<=v\s*) - 前面有一个字母v,后跟一些(或没有)空格
  • (?<T>\d+) - 一系列数字,并将其捕获为命名项目(T)以便稍后替换

前瞻和后瞻表达式假设名称或一天永远不会以字母v结尾(英语为true,可能至少包含其他一些语言,但不一定全部),但同时允许变量空格要么是团队号码之间v的宽度。如果那个空格肯定是固定的,那么这可以用来改进前瞻和后看字符串。

这里的另一个变化是我从之前创建的阵列中创建了一个Dictionary个团队,只有当团队数量变得相对较大时才能产生明显效果。可见效果是完成了简单的字典查找,而不是为每个团队进行数组的线性扫描。

结果代码如下所示:

static Dictionary<string, string> teamDb =
    teams.ToDictionary(t => t.Id, t => t.Name);
public static void Test3(string text)
{
    var result = Regex.Replace(text,
                                @"((?<T>\d+)(?=\s*v))|((?<=v\s*)(?<T>\d+))",
                                new MatchEvaluator(
                                    m => teamDb[m.Groups["T"].Value]
                                ));
    Console.WriteLine("Test3: {0}", result);
}

在所有三种情况下,如果输入字符串包含未出现在查找表中的团队编号,则代码仍然存在未解决的问题(在尝试获取{{1时,程序将使用NullReferenceException崩溃但是,解决这个问题需要决定你想要在输出字符串中放入什么。

-
1 没有一个简单的程序。

答案 4 :(得分:0)

这是我的版本:

/((\d+)(\b)(?![:]))/g

哪个将起作用:

string text = "Monday 11:30am,11 v 2,3 v 4,5 v 6";
var result = Regex.Replace(text, @"((\d+)(\b)(?![:]))", "Team$1");

<强> Online Demo

\d+ 会捕获尽可能多的数字 (\b)(?![:]) 会通过搜索:来排除与时间相关联的数字。
(\b) 是必需的,因为所谓的+的贪婪行为。为了确保预先评估整数\b是必需的。

或基于修改

string text = "Monday 11:30am,11 v 2,3 v 4,5 v 6";
var result = Regex.Replace(text, @"((\b)([\d]+)(\b)(?![:]))", new MatchEvaluator(
delegate(Match m)
{
    return "Team" + m.Value;   /*take value and find the proper team;*/
} ));