使用带有子组的组的 Vala 正则表达式不断以分段错误结束

Vala regex using groups with subgroups keeps ending in a segmentationfault

真的很简单。我正在尝试使用正则表达式来识别 vcard 字符串一行中的某些 属性 值。

所以,这是代码:

int main(string[] args){

string input = "TEL;VALUE=uri;PREF=1;TYPE=\"voice,home\":tel:+1-555-555-5555;ext=5555";



string regString = "(tel:(?<phnum>.*);)*(?<pref>PREF=1;)*";

Regex regex = new Regex(regString);
MatchInfo match;

regex.match(input_end, 0, out match);

stdout.printf(match.fetch_named("phnum"));

stdout.printf(match.fetch_named(pref));

return 0;

}

我真正想做的是,当标签 phnum 出现在输入中时,它适用于字符子组(因此 * 位于组的外部)。所以当我这样做时:match.fetch_named("phnum") 返回值将是:“+1-555-555-5555”。

我只是遇到分段错误,尽管正则表达式测试器应用似乎可以很好地接受该模式。

您的正则表达式应缩短为:

tel:(?<phnum>.*);$

现在 'phnum' 组将包含 phone 个号码。

printf 首先采用格式字符串。您需要将它们更改为:

stdout.printf("%s\n", match.fetch_named("phnum"));

stdout.printf("%s\n", match.fetch_named("pref"));

如果格式字符串为空,printf 将出现段错误。

如果你不想打扰格式字符串,你可以使用FileStream.puts,但你仍然需要一个空检查:

if (match.fetch_named("phnum")!=null)
  stdout.puts(match.fetch_named("phnum"));

在想regex.match(input_end也应该是regex.match(input

在不考虑 phone 数字的确切格式的情况下,一种可能的解决方案是匹配 character class 中允许的字符并从名为 [=12= 的组中获取值]

tel:(?<phnum>[0-9+-]+)

Regex demo | Test it online

或者更广泛的匹配可能是使用取反字符 class [^ 来匹配您不想要的内容,并从名为 phnum[= 的组中获取值20=]

tel:(?<phnum>[^\r\n;]+)

Regex demo

可以做很多事情来改进 Vala 代码:

  • GLib 的 Regex 绑定到 PCRE 将 return 一条错误消息,提供有关无效正则表达式的一些详细信息。在 Vala 中,可以通过将 new Regex () 放在 try...catch 块中来读取此消息。
  • regex.match() returns true 当找到匹配项时,因此将 regex.match() 包装在 if 语句中会使程序更健壮
  • Vala 具有空合并运算符 ??,这是在存在空值时提供替代值的便捷方式
  • MatchInfo 具有 next() 方法,当与 Vala 的 do {} when () 循环结合使用时,提供了一种安全检索多个匹配项的好方法

您使用的正则表达式需要排除终止符 ;。因此 tel:(?<phnum>[^;|.]*); 将匹配 tel: 之后除 ; 之外的所有字符,直到达到 ;

这是一个将所有这些放在一起的工作示例:

int main () {

  string input = "TEL;VALUE=uri;PREF=1;TYPE=\"voice,home\":tel:+1-555-555-5555;ext=5555";

  string regString = "tel:(?<phnum>[^;|.]*);|PREF=(?<pref>[0-9]*);";
  Regex regex;
  MatchInfo match;
  try {
    regex = new Regex(regString);
    if (regex.match(input, 0, out match)) {
      do {
        stdout.printf("Phone number: %s\n", match.fetch_named("phnum") ?? "None");
        stdout.printf("Preference: %s\n", match.fetch_named("pref") ?? "None");
      }
      while (match.next());
    }
  }
  catch (Error error) {
    print (@"$(error.message)\n");
    return 1;
  }

  return 0;
}

这输出:

Phone number: 
Preference: 1
Phone number: +1-555-555-5555
Preference: None

有两场比赛。有趣的是 phone 数字的第一个匹配 returns 空字符串。这是因为它是一个有效的子模式,但没有匹配任何东西。我不清楚为什么 pref 对于第二场比赛为空。这需要对正则表达式引擎中发生的事情进行更多调查,但希望这足以让您继续学习。