AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 762984
Accepted
Daniel
Daniel
Asked: 2023-12-03 23:11:17 +0800 CST2023-12-03 23:11:17 +0800 CST 2023-12-03 23:11:17 +0800 CST

Sed - 如何替换两个字符串,但保留它们之间的内容?

  • 772

我正在编写一个 shell 脚本来将一些 DokuWiki 页面转换为 MediaWiki 格式,反之亦然。我在脚注方面遇到了一些麻烦。

DokuWiki 有一个插件,可以为 DokuWiki 的基本脚注标记添加扩展功能。其中之一是能够向笔记添加名称并在以后重复使用。例如:

多库维基 媒体维基
[(FOO>This is a footnote.)] <ref name="FOO">This is a footnote.</ref>
[(BAR>Another note in the same paragraph.)] <ref name="BAR">Another note in the same paragraph.</ref>

使用sed可以轻松查找和替换。这是我的脚本与带有“注释名称”的脚注相关的命令:

sed -ri 's@\[\(.*>@<ref name=\"XXX\">@g' dokuwiki-page.txt
sed -ri 's@\)\]@<\/ref>@g' dokuwiki-page.txt

但是,当然,它不会保留名称,它只是将新的通用注释名称“XXX”应用于所有具有名称的注释。因此,在我上面的示例中,结果将是:

多库维基 媒体维基
[(FOO>This is a footnote.)] <ref name="XXX">This is a footnote.</ref>
[(BAR>Another note in the same paragraph.)] <ref name="XXX">Another note in the same paragraph.</ref>

我需要帮助来保留注释名称(示例中的 FOO 和 BAR)。我确实接受除sed之外的其他解决方案。

重要笔记:

  1. 脚注句子可以出现在段落的中间,并且多个带有脚注名称的引用可以出现在同一段落中但具有不同的名称。(又名 Unix 的“非常长的行”的段落)
  2. 我无法拆分命令以[(在第一个命令中替换,>然后在第二个命令中替换,因为 MediaWiki 标记使用了太多的 html 标签(充满 和<)>。一个标签可能会被不正确地替换。
  3. 有一些[(...)]没有>里面的。就像在 中[(This is a nameless note.)]而不是[(My_Note_Name>This is a named note.)].
linux
  • 2 2 个回答
  • 92 Views

2 个回答

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2023-12-04T00:28:07+08:002023-12-04T00:28:07+08:00

    perl使用具有非贪婪重复运算符的正则表达式,这种事情要容易得多:

    perl -i -pe 's{\[\((.*?)>(.*?)\)\]}{<ref name="$1">$2</ref>}g' your-file
    

    请注意,-i和-r是非标准sed选项。-i实际上是perl由一些实现复制的,尽管彼此之间的方式不兼容。

    perl与几种sed实现相反,它对行的大小也没有限制,可以处理 NUL 字符,并且默认情况下按字节处理输入,因此不存在无法在用户区域设置中解码为文本的输入问题。

    如果您的输入可能有一些[(...)]不包含>s,那么您需要调整正则表达式。如果引用标签仅包含word 字符(ASCII 数字和下划线),那么它可能只是:

    perl -i -pe 's{\[\((\w+)>(.*?)\)\]}{<ref name="$1">$2</ref>}g' your-file
    

    另一种方法是找到所有[(...)]并在其中进行替换作为单独的步骤:

    perl -i -pe '
      s{\[\(.*?\)\]}{
        $& =~ s{\[\((.*?)>(.*)\)\]}{<ref name="$1">$2</ref>}r
      }ge' your-file
    

    这也将允许使用将无名注释更改为<ref>nameless</ref>:

    perl -i -pe '
      s{\[\(.*?\)\]}{
        $& =~ s{\[\((?:(.*?)>)?(.*)\)\]}{
          "<ref" . (defined($1) ? qq( name="$1") : "") . ">$2</ref>"
        }re
      }ge' your-file
    

    [(...)]或者使用负向前看运算符来确保在不包含的内容中匹配)]:

    perl -i -pe 's{\[\(((?:(?!\)\]).)*?)>((?1))\)\]}{<ref name="$1">$2</ref>}g' your-file
    
    • 3
  2. Daniel
    2023-12-04T00:22:31+08:002023-12-04T00:22:31+08:00

    最终的SED方式:

    我通过使用sed和正则表达式组找到了解决方案。

    sed -Ei 's/\[\(([[:alnum:]]*)>/<ref name=\"\1\">/g' dokuwiki-page.txt
    sed -Ei 's/\)\]/<\/ref>/g' dokuwiki-page.txt
    

    解释:

    1. 查找带有[(+ letters and numbers in any quantity+的行>
      • 这里的技巧是letters and numbers in any quantity使用: 进行分组([[:alnum:]]*),所以我可以使用 引用完全相同的组\1。这就像将其存储在变量中。
      • 我不能使用.*代替,([[:alnum:]]*)因为它包括其他>. 因此,如果同一段落中有任何其他命名脚注(也称为非常长的行),则正则表达式将包含从第一个脚注到第二个脚注末尾的所有内容。一团糟!
    2. 将所有这些替换为<ref name="+ letters and numbers in any quantity+ ">。
      • 在这里,我使用\1(代表([[:alnum:]]*))来握住它,同时替换它周围的东西。

    阅读建议:

    • 多尔蒂,D. 和罗宾斯,A. (1997)。SED 和 AWK。(第二版)。奥莱利.
    • 0

相关问题

  • 有没有办法让 ls 只显示某些目录的隐藏文件?

  • 使用键盘快捷键启动/停止 systemd 服务 [关闭]

  • 需要一些系统调用

  • astyle 不会更改源文件格式

  • 通过标签将根文件系统传递给linux内核

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve