RegEx模式在这些情况下限制破折号

时间:2015-09-27 12:04:53

标签: regex delphi pattern-matching filenames pascalscript

方案

我使用的是第三方文件重命名软件,该软件是用Delphi编写的,并且支持pascal脚本:http://www.den4b.com/?x=products&product=renamer

应用程序允许使用正则表达式重命名文件。这意味着如果我只需要使用一个RegEx就无法完成文件名所需,那么我可以同时使用各种表达式或pascal脚本代码来容纳文件名,直到我可以正确格式化文件名以满足此需求问题或其他任何事情......

问题

我需要格式化下面的歌曲文件名,在这些文件名中使用" ...特色艺术家" part位于字符串的右侧,我需要将其匹配并将其放置在字符串的左侧部分。

  • Carbin& Sirmark - 对不起壮举。 Sevener
  • Kristjan Cash Cash - Take Me Home Feat。 Bebe Rexha(撤销混音)

为了使这个简单易懂,我们可以想象 tokenize 这样的文件名:

[0]ARTIST   [1]DASH   [2]TRACK   [3]FEAT_ARTIST   [4]POSSIBLE_ADDITIONAL_INFO_INSIDE:()[]{}

然后我需要对RegEx做什么,格式化文件名以按此顺序定位标记

[0]ARTIST   [3]FEAT_ARTIST   [1]DASH   [2]TRACK   [4]POSSIBLE_ADDITIONAL_INFO_INSIDE:()[]{}

我实际上是使用此RegEx执行此操作:

  

\ A([^ - ]的?)\ S - (?)\ S * \ S ([([])((英尺[?。 \ S] |技艺??[\ S] |。设有[\ S])[^(){} []] *)([)]])(+)\ž

替换为:

  

$ 1 $ 4 - $ 2 $ 7

问题从这里开始,因为[0]ARTIST[2]TRACK令牌可能包含破折号,例如此文件名:

  • Dj E-nergy C-21 - 我的超级英雄曲目! feat Dj Ass-hole

然后,如果我错了,请纠正我,但我认为以任何方式解决这个问题都是不可能的,因为机器无法预测何时将一个令牌与另一个令牌分开,这是什么名字或者什么不是,因为我不知道包含文件名的破折号码。

  

出于这个原因,而不是寻找可能导致不良的ingenuos完美   文件名因为内部破折号的数量,我更愿意寻找一个   文件名排除解决方案,通过限制表达式的破折号   应该在文件名中匹配。

问题

以我上面展示的RegEx为例来扩展/改进它,如何排除包含带有短划线的[0]ARTIST[2]TRACK令牌的文件名?

...或者换句话说,当文件名包含多于1个破折号 " ...特色时,我怎么能告诉我的RegEx避免修改文件名艺术家"部分? (不是之后)

基本上,正则表达式应确定在[1]DASH之前是否多次找到[3]FEAT_ARTIST,如果是,则排除该文件名(不要修改它)

我知道如何限制正则表达式组的出现,或多或少像([\-]){1}这样只匹配1个短划线,但我不确定如何在表达式I&#39中实现它;使用。

预期结果

只是一些随机的例子......

仅在[3]FEAT_ARTIST之前的一个短划线,以便我们知道何时将[0]ARTIST[2]TRACK代币分开。

  • 来自:' Carbin& Sirmark - 对不起壮举。 Sevener '
  • To:' Carbin& Sirmark Feat。 Sevener - 抱歉'

仅在[3]FEAT_ARTIST之前的一个短划线,以便我们知道何时将[0]ARTIST[2]TRACK代币分开。使用[4]POSSIBLE_ADDITIONAL_INFO_INSIDE:()[]{}

  • 来自:' 飞行设施 - 心脏病发作。 Owl Eyes(Snakehips Remix)'
  • To:' 飞行设施壮举。猫头鹰眼睛 - 心脏病发作(Snakehips Remix)'

仅在[3]FEAT_ARTIST之前的一个短划线,以便我们知道何时将[0]ARTIST[2]TRACK代币分开。 [4]POSSIBLE_ADDITIONAL_INFO_INSIDE:()[]{}也包含破折号。

  • 来自:' 飞行设施 - 心脏病发作。猫头鹰眼睛[蛇 - 臀部混音] '
  • To:' 飞行设施壮举。猫头鹰眼睛 - 心脏病发作[Snake - hips Remix] '

仅在[0]ARTIST[2]TRACK令牌之间使用一个短划线,但文件名没有[3]FEAT_ARTIST,因此我们无法触摸它。

  • 来自:' Fedde Le Grand - Cinematic '
  • 致:' Fedde Le Grand - Cinematic '

仅在[0]ARTIST[2]TRACK令牌之间使用一个短划线,但[3]FEAT_ARTIST位于[1]DASH之前,因此我们无法触及它。

  • 来自:' Fedde Le Grand Feat。 Denny White - Cinematic '
  • To:' Fedde Le Grand Feat。 Denny White - Cinematic '

[0]ARTIST有短划线,因此我们无法知道何时将[0]ARTIST[2]TRACK令牌分开,因此正则表达式应将其排除在外,以免修改此文件名

  • 来自:' 艺术家姓名 - 跟踪姓名专长'
  • 收件人:' 艺术家姓名 - 跟踪姓名专长'

[2]TRACK有短划线,因此我们无法知道何时将[0]ARTIST[2]TRACK令牌分开,因此正则表达式应将其排除在外,以免修改此文件名

  • 来自:' 艺术家姓名 - Track-Name壮举某人'
  • 收件人:' 艺术家姓名 - Track-Name壮举某人'

[0]ARTIST[2]TRACK令牌有破折号,因此我们无法知道何时将它们分开,因此正则表达式应排除这一点以免修改此文件名。

  • 来自:' Dj E-nergy C-21 - 我的超级英雄曲目! feat Dj Ass-hole '
  • To:' Dj E-nergy C-21 - 我的超级英雄曲目! feat Dj Ass-hole '

[0]ARTIST[2]TRACK令牌有破折号,而[3]FEAT_ARTIST也不存在,此处无处可做。

  • 来自:' Dj E-nergy C-21 - 我的超级英雄曲目!'
  • To:' Dj E-nergy C-21 - 我的超级英雄曲目!'

我希望这有助于理解我的需要。

4 个答案:

答案 0 :(得分:1)

我认为你唯一需要意识到/改变的是“分隔符连字符”和“嵌入连字符”之间存在明显区别。也就是说,没有嵌入的连字符在两个边上都有空格(我希望;你需要验证它)。您需要做的就是将正则表达式的开头从\A([^-]?)\s-\s*更改为\A(.?)\s-\s+ ...

答案 1 :(得分:1)

我将所有文件名放入文本编辑器UltraEdit 22.10版:

Carbin & Sirmark - Sorry Feat. Sevener
Kristjan Cash Cash - Take Me Home Feat. Bebe Rexha (Revoke Remix)
Dj E-nergy C-21 - My Super-hero track! feat Dj Ass-hole
Flight Facilities - Heart Attack Feat. Owl Eyes (Snakehips Remix)
Flight Facilities - Heart Attack Feat. Owl Eyes [Snake--hips Remix]
Fedde Le Grand - Cinematic
Fedde Le Grand Feat. Denny White - Cinematic
Artist-Name - Track Name feat someone
Artist Name - Track-Name feat someone
Dj E-nergy C-21 - My Super-hero track! feat Dj Ass-hole
Dj E-nergy C-21 - My Super-hero track!

使用Perl正则表达式搜索字符串

^(.+) - (.+?) ((?:featuring|feat\.?|ft\.?) +(?:[^\r\n (\[{]| (?![(\[{]))+)

和替换字符串

$1 $3 - $2

这些文件名使用不区分大小写的全部替换修改为

Carbin & Sirmark Feat. Sevener - Sorry
Kristjan Cash Cash Feat. Bebe Rexha - Take Me Home (Revoke Remix)
Dj E-nergy C-21 feat Dj Ass-hole - My Super-hero track!
Flight Facilities Feat. Owl Eyes - Heart Attack (Snakehips Remix)
Flight Facilities Feat. Owl Eyes - Heart Attack [Snake--hips Remix]
Fedde Le Grand - Cinematic
Fedde Le Grand Feat. Denny White - Cinematic
Artist-Name feat someone - Track Name
Artist Name feat someone - Track-Name
Dj E-nergy C-21 feat Dj Ass-hole - My Super-hero track!
Dj E-nergy C-21 - My Super-hero track!

看起来像你想要的。 UltraEdit使用Boost Perl正则表达式库。

如果文件重命名工具也支持负向前瞻和贪婪匹配行为,则表达式可能对此任务有用:

\A(.+) - (.+?) ((?:featuring|feat\.?|ft\.?) +(?:[^ (\[{]| (?![(\[{]))+)

,替换字符串也是:

$1 $3 - $2

搜索字符串的说明:

^ ...开始行 \A ...缓冲区的开始

(.+) -  ...一个贪婪表达式,它匹配任何字符1次或多次(换行符除外)直到最后出现空格 划线 空格在不包括 - 的标记组中,其结果仍然是整个表达式的正匹配。

(.+?)  ...一个非贪婪表达式也位于匹配任何字符(换行符除外)的捕获组中,一次或多次直到下一次出现空格并且......

(?:featuring|feat\.?|ft\.?) + ...字featuring或缩写feat,带或不带点或缩写ft,带或不带点和1个或多个空格。

( ...从第三个捕获组开始。

(?:[^\r\n (\[{]| (?![(\[{]))+ ...与

匹配的非标记组
  • 一个字符正在
    • 回车或换行(仅限UE搜索字符串)或
    • 左括号,或
    • 一个开口的方括号,或
    • 一个大括号

  • 使用负前瞻表达式检查下一个字符的空格
    • 左括号,或
    • 一个开口的方括号,或
    • 一个大括号

一次或多次。换句话说,最后一个表达式匹配文件名末尾的所有内容或([{,不包括留给这些字符的空格以避免获取 space FEAT_ARTIST之后的 space dash

) ...终于结束了第三个捕获组。

编辑1:同时工作(在UltraEdit中)是搜索字符串:

^(.+) - (.+?) ((?:featuring|feat|ft)[ .]+(?:[^\r\n (\[{]| (?![(\[{]))+)

除了featuring.之外,它会使表达更容易一些。

编辑2:同样工作(在UltraEdit中)是搜索字符串:

^((?:.(?! - ))+.) - ((?:.(?! - ))+) ((?:featuring|feat|ft)[ .]+(?:[^\r\n (\[{]| (?![(\[{]))+)

忽略包含两个空格 破折号 空格的所有行左侧FEAT_ARTIST

如果当前字符后面的字符串不是 space dash space ,则此表达式逐字符匹配使用否定前瞻。这是第一个捕获组,允许选择第一个空间 破折号 空间左边的最后一个字符的字符串,但对于第二个捕获组,应该不再是 space dash space ,因为这肯定会导致整个表达式产生负面结果。

答案 2 :(得分:1)

尝试:

^(.+)\s+-\s+(.+?)\s+[fF](t|eat(uring)?)?\.?([^([\])\n]+)(.+)?$

DEMO

并使用替换为:$1 Feat.$5 - $2$6

我尝试使用ReNamer和Regex101,如果艺术家名称中有- + - + ),它也会有效,例如{{1但是,如果标题部分中有这样的片段,它将失败。

artist - name部分在序列空间 - 破折号空间之前使用贪心量词^(.+)\s+-\s+,它被视为艺术家姓名和曲目标题之间的分隔符。所以它会尽可能多地匹配,直到最后一次出现.+,因此,它会“忽略”带有艺术家名字空格的破折号,但是如果这样的元素出现则会无效匹配在曲目标题。所以:

  • - - 它将匹配并且 修改得当,
  • Artist - name - track title feat. someone - 它会失败,就像文字一样 将在最后一个破折号上拆分。

而不是Artist name - track - title feat. someone我使用匹配相似的(ft[.\s]|feat[.\s]|featuring[.\s]),但应该更快地工作(它应该稍微限制回溯)。

在我的演示中,有一个[fF](t|eat(uring)?)?\.?而不是+(如上所述),因为它会在演示中匹配多行,并显示无效结果,但在oneline情况下,就像你的问题一样,它应该工作正常。

答案 3 :(得分:0)

在@ m.cekiera 的正则​​表达式的帮助下,我通过使用pascal脚本解决了这个问题,该脚本在文件名中找到多个破折号时阻止了任何替换:

// Formats an audio filename that has the "...featuring artist" part at the end of filename.
//------------------------------------------------------------------------------------------


// Pseudo-Example:
//
// From: [0]ARTIST_NAME  [1]DASH  [2]TRACK_TITLE  [3]FEAT_ARTIST  [4]POSSIBLE_ADDITIONAL_INFO_INSIDE:()[]{}
// To:   [0]ARTIST_NAME  [3]FEAT_ARTIST  [1]DASH  [2]TRACK_TITLE  [4]POSSIBLE_ADDITIONAL_INFO_INSIDE:()[]{}

// Real-Example:
//
// From: Carbin & Sirmark - Sorry Feat. Sevener.mp3
// To:   Carbin & Sirmark Feat. Sevener - Sorry.mp3

// Known limitations:
//
// • If [0]ARTIST_NAME or [2]TRACK_TITLE parts contains any " - " the script will not work properlly.
//   By default the script prevents any replacement on that kind of filenames, so don't worry.


var
  rgxPattern: string;
  rgxReplace: string;
  dashCount: integer;
  baseName: string;
  extension: WideString;

begin

  baseName  := WideExtractBaseName(FileName)
  extension := WideExtractFileExt(FileName);

  // The regular expression that matches the filename parts.
  // http://stackoverflow.com/questions/32807698/regex-pattern-to-limit-dashes-in-these-circumstances
  rgxPattern := '^(.+)\s+-\s+(.+?)\s+[fF](t|eat(uring)?)?\.?([^([\])\n]+)(.+)?$'
  rgxReplace := '$1 Feat.$5 - $2$6'

  // The amount of " - " that contains the filename.
  dashCount := high(MatchesRegEx(baseName, '\s-\s' , false));

  // If only one " - " is found then...
  If (dashCount = 0) Then
    begin // Do the replacement.
      baseName := ReplaceRegEx(baseName, rgxPattern, rgxReplace, false, true)
      FileName := baseName + extension;
    end;

end.