【问题标题】:perl replacing serialized strings from sql dumpperl 替换 sql 转储中的序列化字符串
【发布时间】:2013-06-28 23:51:20
【问题描述】:

出于网站迁移的目的,我不得不替换 SQL 转储中的 fqdn。我编写了一个应该采用 STDIN 的 perl 过滤器,替换包含应该替换的域名的序列化字符串,用传递给脚本的任何参数替换它,然后输出到 STDOUT。

这是我目前所拥有的:

my $search   = $ARGV[0];
my $replace  = $ARGV[1];
my $offset_s = length($search);
my $offset_r = length($replace);
my $regex    = eval { "s\:([0-9]+)\:\\\"(https?\://.*)($search.*)\\\"" };

while (<STDIN>) {
    my @fs = split(';', $_);
    foreach (@fs) {
        chomp;
        if (m#$regex#g) {
        my ( $len, $extra, $str ) = ( $1, $2, $3 );
        my $new_len = $len - $offset_s + $offset_r;
        $str =~ eval { s/$search/$replace/ };
        print 's:' . $new_len . ':' . $extra . $str . '\"'."\n";
        }
    }
}

过滤器得到传递的数据可能看起来像这样(这取自 wordpress 转储,但我们也应该适应 drupal 转储:

INSERT INTO `wp_2_options` VALUES (1,'siteurl','http://to.be.replaced.com/wordpress/','yes'),(125,'dashboard_widget_options','
a:2:{
s:25:\"dashboard_recent_comments\";a:1:{
s:5:\"items\";i:5;
}
s:24:\"dashboard_incoming_links\";a:2:{
s:4:\"home\";s:31:\"http://to.be.replaced.com/wordpress\";
s:4:\"link\";s:107:\"http://blogsearch.google.com/blogsearch?scoring=d&partner=wordpress&q=link:http://to.be.replaced.com/wordpress/\";
}
}
','yes'),(148,'theme_175','
a:1:{
s:13:\"courses_image\";s:37:\"http://to.be.replaced.com/files/image.png\";
}
','yes')

如果我的$search 中没有任何句点,则正则表达式有效。我试过转义句点,即domain\.to\.be\.replaced,但这没有用。我可能是以一种非常迂回的方式或遗漏了一些明显的东西。任何帮助将不胜感激。

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    由于其中包含变量,因此无需评估 (eval) 您的正则表达式。此外,为了避免像$search 这样的变量的元字符的特殊含义,请使用quotemeta() 函数或在正则表达式中包含\Q\E 之间的变量来转义它们。所以而不是:

    my $regex = eval { "s\:([0-9]+)\:\\\"(https?\://.*)($search.*)\\\"" };
    

    用途:

    my $regex = qr{s\:([0-9]+)\:\\\"(https?\://.*)(\Q$search\E.*)\\\"};
    

    my $quoted_search = quotemeta $search;
    my $regex = qr{s\:([0-9]+)\:\\\"(https?\://.*)($quoted_search.*)\\\"};
    

    对于这一行的建议相同:

    $str =~ eval { s/$search/$replace/ };
    

    【讨论】:

      【解决方案2】:

      您必须将$search 变量中的转义字符\ 加倍,以使插值字符串包含转义句点。

      domain\.to\.be\.replaced -> domain.to.be.replaced(不需要)

      domain\\.to\\.be\\.replaced -> domain\.to\.be\.replaced(正确)。

      【讨论】:

        【解决方案3】:

        我不确定您的 perl 正则表达式是否会替换与旧 DNS 匹配数倍的字符串中的 DNS(在相同的序列化字符串中)。

        对于同样的问题,我使用 bash、sed 和一个大的 perl 正则表达式编写了一个脚本的要点。你可以give it a try

        我使用的正则表达式是这样的(为了便于理解而爆炸,并且以 -7 作为域名长度之间的已知差异):

        perl -n -p -i -e '1 while s#
          ([;|{]s:)
          ([0-9]+)
          :\\"
          (((?!\\";).)*?)
          (domain\.to\.be\.replaced)
          (.*?)
          \\";#"$1".($2-7).":\\\"$3new.domain.tld$6\\\";"#ge;' file
        

        这可能不是最好的,但至少它似乎可以胜任。 g 选项管理包含要清理的多个序列化字符串的行,while 循环重做整个工作,直到序列化字符串中没有替换发生(对于包含多个 DNS 出现的字符串)。我不太喜欢正则表达式来尝试递归。

        【讨论】:

          猜你喜欢
          • 2012-09-21
          • 1970-01-01
          • 2019-03-07
          • 2014-10-06
          • 1970-01-01
          • 2023-02-23
          • 2020-07-23
          • 2019-01-15
          • 2022-01-08
          相关资源
          最近更新 更多