正则表达式从子字符串到另一个子字符串的第一次出现

正则表达式从子字符串到另一个子字符串的第一次出现

我需要从列表中删除 textClipping 文件。不幸的是,有些文件的名称很糟糕,并且包含回车符。我需要 perl 正则表达式来匹配从到的每个路径(/Volumes/包括.textClipping换行符)。

/Volumes/.*\.textClipping捕获前两个.textClipping文件,但不捕获第三个文件(带有换行符)。另外,我能够捕获从第一个/Volumes/到最后一个的所有内容.textClipping,但这也没什么用。

有什么想法吗?非常感谢。

/Volumes/folder/folder/file.doc
/Volumes/folder/folder/file.textClipping
/Volumes/folder/folder/file.doc
/Volumes/folder/folder/file.textClipping
/Volumes/folder/folder/fi  

le.textClipping
/Volumes/folder/folder/file.doc

答案1

你可以这样做:

perl  -0777 -ae '@files = m~(/Volumes/(?:[^/\r\n]+/)+?[^/]+?\.textClipping\R)~g;print scalar(@files)," files found:\n",@files' file.txt

在哪里:

  • -0777以“slurp”模式读取文件
  • -a自动分割模式

正则表达式:

 ~                      : regex delimiter
(                       : start group 1
    /Volumes/           : literally 
    (?:                 : start non capture group
        [^/\r\n]+       : 1 or more any character that is not a slash or line break
        /               : slash
    )+?                 : group repeated 1 or more times, not greedy (ie. the path)
    [^/]+?              : not a slash, 1 or more times, not greedy (ie. the filename)
    \.textClipping      : a dot with the extension
    \R                  : any kind of linebreak
)                       : end group 1
~g                      : regex delimiter, global flag

输出:

3 files found:
/Volumes/folder/folder/file.textClipping
/Volumes/folder/folder/file.textClipping
/Volumes/folder/folder/fi

le.textClipping

如果你想保留所有不以.textClipping

perl  -0777 -i.orig -ape 's~(/Volumes/(?:[^/\r\n]+/)+?[^/]+?\.textClipping\R)~~g' file.txt

输入文件被就地修改(选项-i),原始文件使用扩展名备份.orig

cat file.txt
/Volumes/folder/folder/file.doc
/Volumes/folder/folder/file.doc
/Volumes/folder/folder/file.doc

答案2

我非常感谢大家的回复。感谢您抽出时间。如果我的问题没有表达清楚,我深表歉意。答案比我最初想象的要简单。

需要注意的是,文件名中的回车符或换行符如下:“file(CR)name.textClipping”。Textclipping 文件只是将其中包含的文本作为文件本身的名称,在我的情况下是几个回车符。真麻烦!

尽管如此,这仍然有效: /卷/.*\n*.textClipping/g

这会匹配以“/Volumes/”开头、以“.textClipping”结尾的字符串以及其间的所有内容。

再次感谢您的建议。

答案3

我无法从你的问题中判断换行符可能位于文件名的哪个位置,所以我假设它们可能位于任何地方。这使得匹配更具挑战性。

最简单的解决方案可能是在删除不需要的文件名之前从输入中删除所有换行符。

我制作了这个脚本:

#!/usr/bin/perl                                                                                                                                            
$filename = "filelist.txt";                                                                                                                                
open(FILE, $filename) or die "Cant open $filename\n";                                                                                                      

# Undefine the record separator, so that the entire file will be read into a single string
# instead of an array with records separated by newlines
local $/ = undef;                                                                                                                                          
$lines = <FILE>;                                                                                                                                           
close(FILE);                                                                                                                                               
print "Before\n------\n";                                                                                                                                  
print $lines;                                                                                                                                              

# Remove all newlines                                                       
$lines =~ s/\n+//g;                                                                                                                                        
# Remove all "textClipping" files
$lines =~ s/\/Volumes\/[^ ]*.textClipping//g;                                                                                                              
# Turn multiple consecutive spaces into single spaces
$lines =~ s/ +/ /g;                                                                                                                                        

print "After\n-----\n";                                                                                                                                    
print "$lines\n";     

并将您的示例作为 filelist.txt 输入其中:

/Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/fi
le.textClipping /Volumes/folder/folder/file.doc

输出结果如下:

Before
------
/Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/fi
le.textClipping /Volumes/folder/folder/file.doc
After
-----
/Volumes/folder/folder/file.doc /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.doc

最后,我认为您应该非常谨慎地使用您在问题中建议的模式:

/Volumes/.*.textClipping

因为 . 会捕获除换行符之外的任何字符,但包括空格。我按照您的问题建议在此输入上运行了该模式:

/Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/fi
le.textClipping /Volumes/folder/folder/file.doc

并得到了这个输出,我不认为这是你想要的:

/Volumes/folder/folder/fi
le.textClipping /Volumes/folder/folder/file.doc

编辑:您最近发布了一个答案来回答您自己的问题,您再次陷入了这个陷阱,但我没有足够的声誉来发表评论。我强烈建议您考虑使用;而不是/Volumes/.*\n*.textClipping/g(这将匹配空格,因此可能一次删除多个文件名) ;将匹配所有内容/Volumes/[^ ]*\n*.textClipping/g[^ ]*除了空格。

相关内容