【问题标题】:Perl Regex Remove Hyphen but Ignore Specific Hyphenated wordsPerl Regex 删除连字符但忽略特定的连字符
【发布时间】:2016-07-16 16:52:07
【问题描述】:

我有一个 perl 正则表达式,可以将连字符转换为空格,例如:-

$string =~ s/-/ /g;

我需要修改它以忽略特定的连字符短语,而不是替换连字符,例如在这样的字符串中:

"use-either-dvi-d-or-dvi-i"

我不希望替换 dvi-d 和 dvi-i 中的连字符,所以它显示为:

"use either dvi-d or dvi-i"

我尝试了各种负面的前瞻匹配,但都失败了。

【问题讨论】:

  • 你试过什么? dvi-idvi-d 是您要排除的唯一短语吗?还是有他们的“白名单”?
  • 其实白名单可能会更好,因为我可能需要保留其他连字词

标签: regex perl strip


【解决方案1】:

您可以将此 PCRE 正则表达式与动词 (*SKIP)(*F) 一起使用以跳过匹配中的某些单词:

dvi-[id](*SKIP)(*F)|-

RegEx Demo

由于使用了(*SKIP)(*F),这将跳过单词dvi-idvi-d进行拆分。

对于您的代码:

$string =~ s/dvi-[id](*SKIP)(*F)|-/ /g;

Perl Code Demo


还有一个基于替代外观的解决方案

/(?<!dvi)-|-(?![di])/

这基本上意味着如果它前面没有dvi或者如果它后面没有di,则匹配连字符,因此当我们在LHS上有dvi时确保不匹配-[di] 在 RHS 上。

Perl 代码:

$string =~ s/(?<!dvi)-|-(?![di])/ /g;

Perl Code Demo 2

【讨论】:

  • 您的 regEX 演示输出(使用-dvi-d 或-dvi-i)与预期的输出不符。
  • 我不认为我可以在 perl 中使用 (*SKIP),它不喜欢吗?
  • 它绝对适用于perl, here is a working perl demo
  • 我还添加了一个基于环视的解决方案。
【解决方案2】:
$string =~ s/(?<!dvi)-(?![id])|(?<=dvi)-(?![id])|(?<!dvi)-(?=[id])/ /g;

仅使用(?&lt;!dvi)-(?![id]) 时,您还将排除dvi-xx-i,其中x 可以是任何字符。

【讨论】:

  • 这是什么?你为什么要使用交替?
  • 我添加了一个解释。
  • 可能不是i-i,你不知道。
  • OP 说I wish to NOT replace the hyphen in dvi-d and dvi-i ..你为什么要考虑字符串i-i
  • 没错,他说的是只将dvi-ddvi-i排除在比赛之外。
【解决方案3】:

您不太可能得到一个简单直接的正则表达式解决方案。但是,您可以尝试以下方法:

#!/usr/bin/env perl

use strict;
use warnings;

my %whitelist = map { $_ => 1 } qw( dvi-d dvi-i );

my $string = 'use-either-dvi-d-or-dvi-i';

while ( $string =~ m{ ( [^-]+ ) ( - ) ( [^-]+ ) }gx ) {
    my $segment = substr($string, $-[0], $+[0] - $-[0]);
    unless ( $whitelist{ $segment } ) {
        substr( $string, $-[2], 1, ' ');
    }
    pos( $string ) = $-[ 3 ];
}

print $string, "\n";

@- 数组包含匹配组的起始偏移量,@+ 数组包含结束偏移量。在这两种情况下,元素 0 指的是整个匹配。

我不得不求助于because of how \G works

还要注意s/// 将拒绝覆盖已被替换的部分替换;所以例如这将在第一次迭代后停止,而不是通过字符串向后迭代:

   $_ = "123456789";
   pos = 6;
   s/.(?=.\G)/X/g;
   print;     # prints 1234X6789, not XXXXX6789

也许@tchrist 可以弄清楚如何让各种断言服从他的意愿。

【讨论】:

    【解决方案4】:

    我们可以使用 negative Look-aheadnegative Look-behind

    忽略特定的词

    例子:

    (?!pattern)
    is a negative look-ahead assertion
    

    在你的情况下,模式是

    $string =~ s/(?<!dvi)-(?<![id])/ /g;
    

    输出:

    use either dvi-d or dvi-i
    

    参考:http://www.perlmonks.org/?node_id=518444

    希望这会对你有所帮助。

    【讨论】:

    • 它不会在dvi-abc上拆分
    • 添加\+ 将解决您的问题。早期模式仅适用于用户示例。
    • \w 匹配文字+ 后转义\+
    • 解决这类问题有很多不同的方法。例如,[0-9,a-z,A-Z]\+ 代替 \w\+ 也可以。
    • 仍在试图找出我的代码有什么问题以及为什么社区人士给出负面反馈。这实际上让我失去了贡献的动力。
    猜你喜欢
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-03
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    相关资源
    最近更新 更多