【问题标题】:find specific pattern of digits in a string在字符串中查找特定的数字模式
【发布时间】:2022-01-17 21:10:45
【问题描述】:

考虑以下字符串:

"via caporale degli zuavi 278a , 78329" 

"autostrada a1 km - 47"

我正在寻找可以存在(第一个示例)或不存在(第二个示例)的特定序列

特别是,我正在寻找一个可以长 1 到 4 位的数字序列,并且可以后跟一个字母,但在字符串中也不能有子字符串“km”。所以在我之前的例子中,“278a”是有效的,但其余的数字序列不是。

到目前为止,我所做的如下:

因为我知道任何包含“km”的字符串都是无效的,所以我应用了这段代码:

if(!stripped.ToLower().Contains("km"))
{
    // apply Regex
}
else
    // string not valid, move on

我知道这个正则表达式会给我所有的数字序列:Regex.Matches(t, @"\d+");,但这还不够。我该如何从这里开始?

编辑:为了进一步澄清,当一个数字序列后跟一个字母时,该字母必须是下一个字符(所以没有空格或其他任何东西)

Edit2:注意数字序列后面可以跟字母也可以不跟(所以278a和278一样有效)

【问题讨论】:

  • 78329 在第一个例子中有效吗?
  • 是否有多个匹配项?
  • @OlivierJacot-Descombes 否,因为有 5 个连续数字
  • @WiktorStribiżew 不,如果有序列它只有 1

标签: c# regex string


【解决方案1】:

你可以左右断言not km,并捕获1-4个数字0-9在一个组中并匹配一个char a-zA-Z:

(?<!\bkm\b.*)\b[0-9]{1,4}[A-Za-z]?\b(?!.*\bkm)
  • (?&lt;!\bkm\b.*) 断言不向左公里
  • \b[0-9]{1,4}[A-Za-z]\b 匹配 1-4 位 0-9 并匹配单个字符 A-Za-z
  • (?!.*\bkm) 断言不向右公里

.NET Regex demo

string pattern = @"(?<!\bkm\b.*)\b[0-9]{1,4}[A-Za-z]?\b(?!.*\bkm)";
string input = @"via caporale degli zuavi 278a , 78329
via caporale degli zuavi 277 , 78329
via caporale degli zuavi 279a , 78329 km
km via caporale degli zuavi 280a , 78329
autostrada a1 km - 47";

foreach (Match m in Regex.Matches(input, pattern))
{
    Console.WriteLine(m.Value);
}

输出

278a
277

如果预期只有 1 个匹配项,您还可以排除整个字符串中的 km,并使用捕获组以及 Regex.Match

^(?!.*\bkm\b).*\b([0-9]{1,4}[A-Za-z]?)\b

Regex demo

【讨论】:

  • 问题是如果我有 278 而不是 278a,这个正则表达式将不起作用。正如我在问题中所说,序列后面可以跟一个字母
  • @DanieleSartori 模式匹配数字后面的字母,您可以将字母设为可选,如(?&lt;!\bkm\b.*)\b([0-9]{1,4})[A-Za-z]?\b(?!.*\bkm)
  • 如果我有 278a 它只返回 278?
  • @DanieleSartori 你也想要a吗?
  • @DanieleSartori 已更新,现在无论有无字母都匹配。
【解决方案2】:

你可以使用

^(?!.*(?<!\p{L})km\b)(?:.*\D)?(\d{1,4})(?=\p{L}?\b)

请参阅.NET regex demo详情

  • ^ - 字符串开头
  • (?!.*(?&lt;!\p{L})km\b) - 不允许 km 在单词前面没有任何字母并且后面不允许有字母数字/下划线在字符串中的任何位置
  • (?:.*\D)? - 除换行符之外的任意零个或多个字符的可选序列,尽可能多,然后是非数字字符
  • (\d{1,4}) - 第 1 组:一到四位数
  • (?=\p{L}?\b) - 紧邻右侧,应该有一个可选字母,后面没有任何字母数字或连接符标点符号(如 _)。

C# demo

var l = new List<string> {"via caporale degli zuavi 278a , 78329","autostrada a1 km - 47"};
foreach (var t in l) 
{
    var rx = @"^(?!.*(?<!\p{L})km\b)(?:.*\D)?(\d{1,4})(?=\p{L}?\b)";
    var match = Regex.Match(t, rx, RegexOptions.ECMAScript)?.Groups[1].Value;
    if (!string.IsNullOrEmpty(match))
    {
        Console.WriteLine($"There is a match in '{t}': {match}");
    } 
    else
    {
        Console.WriteLine($"There is no match in '{t}'.");
    }
}

输出:

There is a match in 'via caporale degli zuavi 278a , 78329': 278
There is no match in 'autostrada a1 km - 47'.

RegexOptions.ECMAScript 选项用于使 \d 仅匹配 ASCII 数字(但它不影响 \p{L})。

【讨论】:

  • 问题是如果我有 278 而不是 278a,这个正则表达式将不起作用。正如我在问题中所说,序列后面可以跟一个字母
  • @DanieleSartori 我更新了解决方案,即使字符串中有12km(将发生故障)也可以返回单个匹配项(如果存在有效匹配项)。
猜你喜欢
  • 2013-11-14
  • 1970-01-01
  • 1970-01-01
  • 2015-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多