【问题标题】:Regex to match only strings ending with a specific word and not containing other words正则表达式仅匹配以特定单词结尾且不包含其他单词的字符串
【发布时间】:2016-01-15 09:00:54
【问题描述】:

我尝试制作一个正则表达式来匹配以单词“Remixes”结尾的字符串,但前提是它前面没有某些单词和字符。我想出了以下具有不同结果的正则表达式,但两者都不完全匹配:

^(\w+)((?!\&|\+|And|The|Of|Various|House|Unreleased|Selected).)\s(Remixes)$

这会排除字符串中的所有关键字,但当它包含多个单词时不包括:Think Twice Remixes 或当它前面有一个单词时:Various Remixes

^(.*)((?!\&|\+|And|The|Of|Various|House|Unreleased|Selected).)\s(Remixes)$

这不包括以下测试示例:Fill Me Up + Remixes,但不包括其他带有排除关键字的示例,例如 Sides & Remixes

如果排除单词是唯一且第一个前面的单词,我如何使第一个字符串匹配具有多个前面单词的字符串而不匹配它?

【问题讨论】:

  • 必须是单个正则表达式吗?因为老实说,虽然您可以可能完成这项工作,但如果您实际使用脚本,解决方案就不会那么难看。
  • 我觉得你可以用^(?!.*(?:&|\+|\b(?:And|The|Of|Various|House|Unreleased|Selected)\b)).*\bRemixes$
  • 我试过了,但它与关键字不匹配,并且没有我想要保留的前面单词的组。我也看不到在哪里指定该组
  • 您是否在寻找后视镜?试试regex101 with this pattern(如果不区分大小写,请添加i 标志)。
  • @bobblebubble 这太完美了!我添加了一个分组以使其对我有用。谢谢你的帮助。 ^(.+)(?

标签: regex regex-lookarounds regex-greedy


【解决方案1】:

老实说,我不会。 regex 是一个强大的工具,你可以用它做很多事情,但是当你不尝试“单一正则表达式”每个问题时,你的代码会变得更加简单和清晰。

对于您的示例,我很想使用 perl 的 grep 函数,它可以让您指定复合条件:

 my @filtered = grep { m/Remixes$/ 
                     and not   
                        m/(And
                             |The
                             |Of
                             |Various
                             |House
                             |Unreleased
                             |Selected
                         )\s*.?\s+Remixes/xi } @list_of_things

例如:

#!/usr/bin/env perl
use strict;
use warnings;

#set up a list of words to exclude when prefixing "Remix"
#qw is perl's "quote words" and lets you specify whitespace delimited values. 
my @exclude_remix_prefix = qw ( And
    The
    Of
    Various
    House
    Unreleased
    Selected );

#turn that into a sub regex (qr 'compiles' a regex). 
my $exclude = join( "|", @exclude_remix_prefix );
$exclude = qr/($exclude)\s+Remixes/i;

#read from the <DATA> filehandle, 
#but you could use <> to read from STDIN/filenames like 'sed/grep' do. 
my @filtered = grep { m/Remixes$/i and not m/$exclude/i; } <DATA>;

print @filtered;

__DATA__
Fill Me Up + Remixes
Sides & Remixes
Something Selected remixes

输出:

Fill Me Up + Remixes
Sides & Remixes

(给我一些应该/不应该匹配的示例,我会扩展)

我们可能会偏离您原来的用例,但如果您想创建一个转换模式:

#!/usr/bin/env perl
use strict;
use warnings;

use Data::Dumper;

my @exclude_remix_prefix = qw ( And
    The
    Of
    Various
    House
    Unreleased
    Selected );

my $exclude = join( "|", @exclude_remix_prefix );
$exclude = qr/($exclude)\s+Remixes/i;

my %transform = map { m/$exclude/ ? () :  m/(.*)/ =>  m/(.*)\s+Remixes/ ; } <DATA>;
print Dumper \%transform; 

__DATA__
Euterpeh Remixes
The Beauty And The Beast Remixes
Think Twice Remixes
Stop And Reset Remixes

这会专门生成一个哈希,其中包含:

$VAR1 = {
          'The Beauty And The Beast Remixes' => 'The Beauty And The Beast',
          'Think Twice Remixes' => 'Think Twice',
          'Euterpeh Remixes' => 'Euterpeh',
          'Stop And Reset Remixes' => 'Stop And Reset'
        };

您或许可以使用它来生成一系列重命名操作?

或者如果你只是想“到位”一些操作,那么一个for循环:

for ( <DATA> ) { 
    chomp; 
    next if m/$exclude/; 
    print "rename ", m/(.*)\s+Remixes/, " ", m/(.*)/,"\n";
}

(好吧,我知道“重命名”并不是你想要做的,但是......)

【讨论】:

  • 感谢您的工作,不幸的是我使用的程序(MP3tag)仅支持单个正则表达式。我可以制作单独的正则表达式,但仅此而已。示例输入和所需输出如下:
  • grep 正在过滤列表以包含/排除与您的模式匹配的内容。如果您还需要转换匹配项,您可以使用 map 执行非常类似的操作。但我需要一个输入和所需输出的示例。
  • 匹配示例:Euterpeh Remixes美女与野兽 RemixesThink Twice Remixes停止并重置混音以更改为 (.*)(混音)
猜你喜欢
  • 1970-01-01
  • 2016-12-06
  • 2012-01-01
  • 1970-01-01
  • 2016-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多