【问题标题】:Renaming files with criteria使用标准重命名文件
【发布时间】:2020-12-29 08:11:06
【问题描述】:

需要一些建议。我正在尝试用正则表达式做一些可能不可能的事情,如果可能的话,这已经超出了我的想象。我什么都做不了。我正在尝试为我的 PDF 文件创建一个标记系统。所以如果我有这个文件名:

"csharp 8 in a nutshell[studying programming csharp ebooks].pdf"

我希望 '[ ]' 中的所有单词都包含一个 '@'。所以上面的文件名应该是这样的:

"csharp 8 in a nutshell[@studying @programming @csharp @ebooks].pdf"

问题是将“@”保留在“[]”中。例如,我宁愿文件名最前面的“csharp”没有“@”。

另外,我正在使用一个名为“批量重命名实用程序”的批量重命名器来帮助我。

  1. 可以这样做吗?
  2. 如果可以的话,有什么提示吗?

谢谢。

【问题讨论】:

    标签: regex file rename


    【解决方案1】:

    我假设最多有一个括号分隔的子字符串。

    当使用Perl(单击“Perl”然后检查全局和大小写不同的选项)Ruby,Python 的替代正则表达式引擎 R 时,您可以将以下正则表达式的零长度匹配替换为 '@' perl=true 或使用 PCRE 正则表达式引擎的语言,其中包括 PHP。除了 Ruby,需要设置区分大小写 (\i) 和通用 (\g) 标志。 Ruby 只需要大小写无关标志。

    r = /(?:^.*\[ *|\G(?<!^)|[a-z]+ +)\K(?<=\[| )(?=[a-z][^\[\]]*\])/
    

    例如,如果使用 Ruby,则会执行

    str = "csharp 8 in a nutshell[studying programming csharp ebooks].pdf"
    str.gsub(r,'@')
      #=> "csharp 8 in a nutshell[@studying @programming @csharp @ebooks].pdf"
    

    我相信我上面提到的所有语言都允许从命令行运行一个简短的脚本。 (我在下面提供了一个 Ruby 脚本。)

    正则表达式引擎执行以下操作。

    (?:                : begin non-capture group
      ^.*\[ *          : match beginning of string then 0+ characters then '['
                         then 0+ spaces
      |                : or
      \G               : asserts the position at the end of the previous match
                         or at the start of the string for the first match
      (?<!^)           : use a negative lookbehind to assert that the current
                         location is not the start of the string
      |                : or
      [a-z]+ +         : match 1+ letters then 1+ spaces
    )                  : end non-capture group
    \K                 : reset beginning of reported match to current location
                         and discard all previously-matched characters from match
                         to be returned
    (?<=               : begin positive lookbehind
      \[|[ ]           : match '[' or a space
    )                  : end positive lookbehind
    (?=                : begin positive lookahead
      [a-z][^\[\]]*\]  : match a letter then 0+ characters other than '[' and ']'
                         then ']'
    )                  : end positive lookahead
    

    另一种可能性(以 Ruby 为例)是将字符串分成三段,修改中间的一段,然后重新连接:

    first, mid, last = str.split /(?<=\[)|(?=\])/
      #=> ["csharp 8 in a nutshell[",
      #    "studying programming csharp ebooks",
      #    "].pdf"]
    first + mid.gsub(/(?<=\A| )(?! )/,'@') + last
      #=> "csharp 8 in a nutshell[@studying @programming @csharp @ebooks].pdf"
    

    split 使用的正则表达式为:“匹配前面为 '[' 的(零宽度)字符串((?&lt;=\[) 是一个正向后视)或后面跟着@987654335 @((?=\]) 是一个正向预测。)通过匹配零宽度字符串split 不会删除任何字符。

    gsub 的正则表达式读取,“匹配一个零宽度字符串,该字符串位于字符串的开头或前面有一个空格,后面跟着一个不是空格的字符((?! ) 是一个 negative lookahead)。也可以写成/(?&lt;![^ ])(?! )/(?&lt;![^ ]) 是一个negative lookbehind)。

    一个变种:

    first + mid.split.map { |s| '@' + s }.join(' ') + last
      #=> "csharp 8 in a nutshell[@studying @programming @csharp @ebooks].pdf"
    

    我创建了一个名为 'in' 的文件,其中包含以下两行:

    Little [Miss Muffet sat on her] tuffet
    eating her [curds and] whey
    

    这是一个 (Ruby) 脚本示例,可以从命令行运行以执行必要的替换。

    ruby -e "File.open('out', 'w') do |fout|
              File.foreach('in') do |str|
                first, mid, last = str.split(/(?<=\[)|(?=\])/)
                fout.puts(first + mid.gsub(/(?<=\A| )(?! )/,'@') + last)
              end
            end"
    

    这会生成一个名为 'out' 的文件,其中包含这两行:

    Little [@Miss @Muffet @sat @on @her] tuffet
    eating her [@curds @and] whey
    

    【讨论】:

      【解决方案2】:

      批量重命名实用程序不支持替换多个匹配项,您只能匹配整个文件名并使用捕获组/反向引用执行替换。

      由于您使用的是 Windows,我建议使用 Powershell:

      cd 'C:\YOUR_FOLDER\HERE'
      Get-ChildItem -File | Rename-Item -NewName { $_.Name -replace '(?<=\[[^][]*?)\w+(?=[^][]*])','@$&' } 
      

      参见this regex demoproof it works with .NET regex flavor

      • (?&lt;=\[[^][]*?) - 在此位置之前,必须有一个 [,然后是除 [] 之外的任意数量的字符,尽可能少
      • \w+ - 1+ 个单词字符
      • (?=[^][]*]) - 在此位置之后,必须有除 [] 之外的任意数量的字符,尽可能多,然后是 ] 字符。

      替换为@ + 整个匹配值 ($&amp;)。

      你也可以使用

      Get-ChildItem -File | Rename-Item -NewName { $_.Name -replace '(\G(?!\A)[^][\w]+|\[)(\w+)','$1@$2' }
      

      参见this regex demo.NET regex test

      • (\G(?!\A)[^][\w]+|\[) - 第 1 组 ($1):上一场比赛的结束和除 ][ 和 word 字符之外的 1+ 个字符,或 [ 字符
      • (\w+) - 第 2 组 ($2):一个或多个单词字符。

      如果您只想重命名 *.pdf 文件,请将 Get-ChildItem -File 替换为 Get-ChildItem *.pdf

      【讨论】:

      • 谢谢。我会试试看。
      • 这非常有效。我认为你的帮助还不够。我想我必须将 regex 和 powershell 放在我的学习清单上。 Powershell 我不知道它可以做这样的事情。
      猜你喜欢
      • 1970-01-01
      • 2013-01-12
      • 1970-01-01
      • 1970-01-01
      • 2013-12-21
      • 2016-05-29
      • 2011-08-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多