【问题标题】:Why isn't this regex executing?为什么这个正则表达式不执行?
【发布时间】:2021-05-04 19:34:56
【问题描述】:

我正在尝试将我的个人 wiki 从 Foswiki 转换为 Markdown 文件,然后再转换为 JAMstack 部署。 Foswiki 使用平面文件并以以下格式存储元数据:

%META:TOPICINFO{author="TeotiNathaniel" comment="reprev" date="1571215308" format="1.1" reprev="13" version="14"}%

我想使用 git repo 进行版本控制,并且会担心稍后将其链接到文章元数据。此时我只想将这些块转换为如下所示的内容:

---
author: Teoti Nathaniel
revdate: 1539108277
---

经过一些调整,我构建了以下正则表达式:

author\=\['"\]\(\\w\+\)\['"\]\(\?\:\.\*\)date\=\['"\]\(\\w\+\)\['"\]

根据regex101 这可行,我的两个捕获组包含所需的结果。尝试实际运行它:

perl -0777 -pe 's/author\=\['"\]\(\\w\+\)\['"\]\(\?\:\.\*\)date\=\['"\]\(\\w\+\)\['"\]/author: $1\nrevdate: $2/gms' somefile.txt

只有这个:

>

我之前的尝试(如果细节没有按特定顺序会中断)看起来像这样并正确执行:

perl -0777 -pe 's/%META:TOPICINFO\{author="(.*)"\ date="(.*)"\ format="(.*)"\ (.*)\}\%/author:$1 \nrevdate:$2/gms' somefile.txt

我认为这是一个转义字符问题,但无法弄清楚。我什至去找this tool 以确保它们是正确的。

强行让我理解这里的方式既低效又令人沮丧,所以我向社区寻求帮助。

【问题讨论】:

  • 提示:如果不使用^$/m 将毫无用处

标签: regex perl markdown foswiki


【解决方案1】:

第一个主要问题是您试图在程序中使用单引号 ('),而该程序正以单引号传递给 shell。

使用'\'' 转义程序中' 的任何实例。如果引号恰好是单个双引号字符串文字或正则表达式文字(就像程序中每个实例的情况一样),您也可以使用 \x27

perl -0777pe's/author=['\''"].../.../gs'
perl -0777pe's/author=[\x27"].../.../gs'

【讨论】:

    【解决方案2】:

    我会尝试将其分解为干净的数据结构,然后对其进行处理。通过将数据处理与打印分开,您可以稍后修改以添加额外的数据。它也使它更具可读性。请看下面的例子

    #!/usr/bin/env perl
    use strict;
    use warnings;
    ## yaml to print the data, not required for operation
    use YAML::XS qw(Dump);
    my $yaml;
    
    my @lines = '%META:TOPICINFO{author="TeotiNathaniel" comment="reprev" date="1571215308" format="1.1" reprev="13" version="14"}%';
    
    for my $str (@lines )
    {
        ### split line into component parts
        my ( $type , $subject , $data ) = $str =~ /\%(.*?):(.*?)\{(.*)\}\%/;
        ## break data in {} into a hash
        my %info = map( split(/=/),  split(/\s+/, $data) );
    
        ## strip quotes if any exist
        s/^"(.*)"$/$1/ for values %info;
    
        #add to data structure
        $yaml->{$type}{$subject} = \%info;
    }
    ## yaml to print the data, not required for operation
    print Dump($yaml);
    
    ## loop data and print
    for my $t (keys %{ $yaml } ) {
        for my $s (keys %{ $yaml->{$t} } ) {
            print "-----------\n";
            print "author: ".$yaml->{$t}{$s}{"author"}."\n";
            print "date: ".$yaml->{$t}{$s}{"date"}."\n";
        }
    }
    

    【讨论】:

      【解决方案3】:

      好吧,我一直在玩弄它,将执行减少到一个术语并扩展。我很快就到了这里:

      $ perl -0777 -pe 's/author=['\"]\(\\w\+\)['"](?:.*)date=\['\"\]\(\\w\+\)\['\"\]/author\: \$1\\nrevdate\: \$2/gms' somefile.txt
      
      Unmatched [ in regex; marked by <-- HERE in m/author=["](\w+)["](?:.*)date=\["](\w+)[ <-- HERE \"\]/ at -e line 1.
      

      这最终把我带到了这里:

      perl -0777 -pe 's/author=['\"]\(\\w\+\)['"](?:.*)date=['\"]\(\\w\+\)['\"]/\nauthor\ $1\nrevdate\:$2\n/gms' somefile.txt
      

      这会产生混乱的输出但有效。 (注意:输出是概念验证,现在可以在 Python 脚本中使用,以编程方式生成 Markdown 元数据。

      感谢 StackOverflow 成为我的橡皮鸭。希望这对某人、某处、某时有用。

      【讨论】:

      • perl -0777 -pe 替换为printf %s。你的程序不是你想象的那样。您将以下内容传递给perls/author=["](\w+)["](?:.*)date=["](\w+)[\"]/\nauthor\ $1\nrevdate\:$2\n/gms。请注意缺少单引号。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-27
      • 1970-01-01
      • 1970-01-01
      • 2013-12-05
      • 1970-01-01
      相关资源
      最近更新 更多