【问题标题】:Ignoring white-spaces during pattern matching using a variable在使用变量进行模式匹配期间忽略空格
【发布时间】:2014-05-28 09:41:12
【问题描述】:

考虑如下两个文件。

文件1:

 Name : John Paul 
Address: 243,  First Floor,
          XYZ - 12345. 
Phone : 555  444 3333 
Name : Mison 
Address: some address like above 
Phone: 444 333 2222

文件2:

Name: John Paul
Address: 243, First Floor,
         XYZ - 12345.
Phone: 555 444 3333

我正在使用 Perl。假设我正在从 File2 读取第一个 Name-to-Phone 块并将其存储在 $var_file2 中(通过逐行读取连接)。 File1 的内容存储在$var_file1 (slurped) 中。考虑我需要将 File2 中的整个 Name-to-Phone 块与 File1 中的块进行比较,并将匹配替换为另一个字符串。我在$var_file2 上使用了quotemeta 函数,因为模式匹配不起作用。

$q_var_file2 = quotemeta($var_file2);
$replace = "replace_text";
$var_file1 =~ s/$q_var_file2/$replace/s;

现在,当模式完全匹配时,上面的代码可以完美运行。但在 File1 或 File2 中可能有额外的空格或没有空格,在进行模式匹配和替换时需要忽略这些空格。

我尝试使用仅匹配非空白字符的 \S。但我想我错过了一些东西。我什至尝试使用变量而不在它们上应用quotemeta

【问题讨论】:

  • 我认为您选择了错误的方法。这些字段必须是手动输入的,因此除了空格之外可能会有很多变化。例如,假设您的地址输入为243 First Floor。然后匹配会因为缺少逗号而失败。甚至会通过输入错误来考虑。您要解决的问题到底是什么?听起来您想通过更改地址来更新数据库?
  • @Borodin 确切的问题是非常机密的,抱歉超出了我的权限。这就是为什么我不得不使用类似的问题上下文来解释。实际上,逗号并不重要。只有空格是个问题。我想用另一个替换整个 Name-to-Phone 块,而不仅仅是块中的地址之类的字段。
  • 您可能会使用两个额外的变量。将您拥有的两个文本复制到其中,然后在每个文本上执行 s/\s+/ /g。这会将所有空白序列转换为单个空格。然后对这些变量进行匹配。另一种选择是在替换表达式的$q_var_file2(.*?)$q_name 部分上执行s/\s+/\\s+/g。替换部分中的$2 来自哪里?
  • 鉴于$var_file1 =~ s/$q_var_file2/$replace/s,我的想法是更改$q_var_file2 的内容,以便将所有空白序列替换为\s+,这将匹配$var_file1 中的任意数量的空白。因此s/\s+/\\s+/g 将任何空白序列更改为三个字符:反斜杠、小写字母和加号。
  • $var_file2 具有在使用 quotemeta($var_file2) 时不会更改的真实空格。我认为s/\s+/\\s+/g 应该应用于$q_var_file2。尝试所有变体。通过这些复杂的操作,您应该在小型数据集上进行测试,并随着代码的执行打印所有值,这样您就可以看到发生了什么以及何时发生。更重要的是,此类打印可让您查看何时发生意外更改以及何时未发生预期更改。 (与print 相比,您可能会发现Data::Dump 提供了更好的输出。)

标签: regex perl


【解决方案1】:

嗯,您只想用\s+ 替换$var_file2 中所有连续的空白序列,同时确保所有其他字符都贯穿quotemeta

$q_re_file = join q{\s+}, map {quotemeta} split /\s+/, $var_file2;

$q_re_file = join q{\s+}, map quotemeta, $var_file2 =~ /\S+/g;

$q_re_file = $var_file2;
$q_re_file =~ s/(\S+)/quotemeta $1/ge;
$q_re_file =~ s/\s+/\\s+/g;

等等。等等

并使用$q_re_file 作为您的正则表达式。

【讨论】:

  • 非常感谢,这行得通!但是说在最坏的情况下,File1File2 中有一个FirstFloor,我们有First Floor,这意味着相同,所以这必须给出一个肯定的匹配。因此,通常我们必须忽略File1File2 中的所有空格并匹配所有其他字符。有没有办法和你的方法一起解决这个问题?
  • @ChrisPetrous 在最终的正则表达式中使用\s*(零个或多个空格字符)代替\s+(一个或多个空白字符)。工作完成。
猜你喜欢
  • 2015-03-10
  • 2013-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-23
  • 2016-10-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多