【问题标题】:Delete text between two quotes in Perl?删除Perl中两个引号之间的文本?
【发布时间】:2026-01-20 06:45:01
【问题描述】:

我以为我已经弄清楚了,但我想在一个文件中找到所有出现的情况,在该文件中,我在两个双引号之间有一些要删除的文本。

我需要先找到一个匹配项,然后获取从第一个双引号到匹配项的所有内容,然后获取所有文本到第二个双引号并将其删除。我不想只在两个双引号之间获取文本,因为它可能不是我想要删除的文件中的内容。

我用过这样的东西:

perl -p -i.bak -e s/bar/foo/g bar.xml

首先进行查找并替换有效。 然后我去了:

perl -p -i.bak -e s/..\/..\/bar\//g bar.xml

这删除了所有内容,但我需要一直继续到第二个双引号,我不知道如何用 Perl 做到这一点。

我认为它会混合一些正则表达式,但我尝试过的任何方法都没有奏效。 bar 之前的部分将始终相同,但文本会在该点之后更改,但是,它将始终以我要删除的部分的第二个双引号结尾。在那之后会再次出现文本。

【问题讨论】:

  • 引号内是否可以有转义引号("a 2\" by 4\" piece of wood")?
  • 你想匹配什么字符串?包括引号。
  • 两个引号之间不会有任何其他引号,只有文本。不幸的是,我无法发布真实数据,但它会类似于:“../../../XXX/XX-XXXX-XXX-XXXXXXX-X.XXX”
  • XML?可能值得发布一个样本 - 可能有更好的方法。 (不一定是真实数据。结构重要,内容不重要)

标签: regex string perl


【解决方案1】:
s/"[^"]*foo[^"]*"//g

如果实际引号之间没有转义引号,并且要删除包含foo 的引号字符串,则可以使用:

"      # Match a quote
[^"]*  # Match any number of characters except quotes
foo    # Match foo
[^"]*  # Match any number of characters except quotes
"      # Match another quote

【讨论】:

  • 不知何故, * 通配符太贪心了,它正在改变整个文件。我是 perl 新手,但这不起作用: perl -p -i.bak -e s/"[^"]*foo[^"]*"//g bar.xml
  • @JamesDrinkard 您使用的是什么操作系统?我注意到您省略了引号。通常引用单行代码中的代码:perl -e 'code'。 linux单引号,windows双引号。如果你省略引号,你就是在搞砸自己。
  • 我正在使用 win7 64 位和最新版本的 ActivePerl for windows。用引号我仍然得到垃圾替换文件中的所有文本,即 ationroursrtitlratorsutilrorationroursrsutulisr...
  • @JamesDrinkard 你不能在 Windows shell 的正则表达式中使用双引号,(也许我应该马上提到)因为你不能在 Windows shell 中转义双引号(如果我正确回忆)。您需要编写一个小脚本。只需将正则表达式放入脚本中并使用perl -pi.bak script.pl bar.xml 调用它
  • @JamesDrinkard:很抱歉没有回复您的 cmets(我正在吃晚饭)。很高兴听到你和 TLP 想通了。我也不知道有人会说 Perl 很简单(正如老话所说,在 RSA 加密前后程序看起来相同的唯一语言)。您可能想研究 Python。在了解 Python 之前,我从未有过 that much fun programming
【解决方案2】:

有些人在询问转义引号。这里有几个技巧。您想忽略转义的引号,如\",而不是引号具有转义转义的字符,如\\"。忽略第一个,我用负面的目光看后面。为了不忽略第二个,我暂时将所有\\ 更改为?。如果您的数据中有 ?,请选择其他内容。

use v5.14;
use utf8;
use charnames qw(:full);

my $regex = qr/
    (?<!\\) "  # a quote not preceded by a \ escape
    (.*?)      # anything, non greedily
    (?<!\\) "  # a quote not preceded by a \ escape
    /x;

while( <DATA> ) {
    # encode the escaped escapes for now
    s/(?:\\){2}/\N{SMILING CAT FACE WITH OPEN MOUTH}/g;
    print "$.: ", $_;

    while( m/$regex/g ) {
        my $match = $1;
        # decode the escaped escapes
        $match =~ s/\N{SMILING CAT FACE WITH OPEN MOUTH}/\\\\/g;
        say "\tfound → $match";
        }
    }

__DATA__
"One group" and "another group"
This has "words between quotes" and words outside
This line has "an \" escaped quote" and other stuff
Start with \" then "quoted" and "quoted again"
Start with \" then "quoted \" with escape" and \" and "quoted again"
Start with \" then "quoted \\" with escape"
Start with \" then \\\\"quoted \\" with escape\\"

输出是:

1: "One group" and "another group"
    found → One group
    found → another group
2: This has "words between quotes" and words outside
    found → words between quotes
3: This line has "an \" escaped quote" and other stuff
    found → an \" escaped quote
4: Start with \" then "quoted" and "quoted again"
    found → quoted
    found → quoted again
5: Start with \" then "quoted \" with escape" and \" and "quoted again"
    found → quoted \" with escape
    found → quoted again
6: Start with \" then "quoted ?" with escape"
    found → quoted \\
7: Start with \" then ??"quoted ?" with escape?"
    found → quoted \\

【讨论】:

    【解决方案3】:

    你输入的文件是.xml - 所以我要说我通常做的事情。

    使用 XML 解析器 - 我喜欢 XML::Twig,因为我认为最初更容易掌握。 XML::LibXML 也不错。

    现在,根据您提出的问题 - like 您正在尝试重写 XML 属性中的文件路径。

    所以:

    #!/usr/bin/env perl/
    
    use strict;
    use warnings;
    
    use XML::Twig;
    
    #my $twig = XML::Twig -> parsefile ( 'test.xml');
    my $twig = XML::Twig -> parse ( \*DATA );
    
    foreach my $element ( $twig -> get_xpath('element[@path]') ) {
       my $path_att = $element -> att('path');
       $path_att =~ s,/\.\./\.\./bar/,,g;
       $element -> set_att('path', $path_att);
    }
    
    $twig -> set_pretty_print('indented_a');
    $twig -> print;
    __DATA__
    <root>
       <element name="test" path="/path/to/dir/../../bar/some_dir">
       </element>
       <element name="test2" nopath="here" />
       <element path="/some_path">content</element>
    </root>
    

    XML::Twig 也非常有用地支持parsefile_inplace 使用“sed 样式”来修改文件。以上是带有一些示例XML 的概念说明 - 有一个更清晰的示例说明您正在尝试做什么,我应该能够改进它。

    【讨论】: