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 / 问题 / 701267
Accepted
Zoltan King
Zoltan King
Asked: 2022-05-04 06:04:15 +0800 CST2022-05-04 06:04:15 +0800 CST 2022-05-04 06:04:15 +0800 CST

如何在整个文件的每一行中替换特定上下文中的字符?

  • 772

我有一个大文件,其中包含以下形式的数百个英语短语:

\phrase
{.   .    .     *     *   }
{I shoul-d've stayed home.}
{aɪ ʃʊd‿əv ˈsteɪd ˈhoʊm.} <- only replace on this line

\phrase
{ .   .   *  }
{Did you eat?}
{dɪdʒjʊʷˈit? ↗} <- only replace on this line

\phrase
{ *    .  *    .    *  .  .    .     *   .  }
{Yeah, I made some pas-ta if you're hun-gry.}
{ˈjɛə, aɪ ˈmeɪd səm ˈpɑ stəʷɪf jər ˈhʌŋ gri.} <- only replace on this line

这是一个 LaTeX.tex文件。我想用符号(十六进制代码)替换r每个音标中的所有字符(通过音标,我的意思是每行后的第三行)。\phraseɹU+0279

在 Emacs 中手动操作对我来说很麻烦。我想知道是否有办法以某种方式定位这些行并自动进行替换。

所有r字符都必须替换为ɹ,也不例外,但仅在拼音r中,在英文/非拼音文本中保持原样。

是否可以通过使用脚本或其他方式以某种方式做到这一点?我的文档中没有换行符,所以转录总是在\phrase​​ . 谢谢!

text-processing replace
  • 8 8 个回答
  • 1624 Views

8 个回答

  • Voted
  1. Archemar
    2022-05-04T06:19:01+08:002022-05-04T06:19:01+08:00

    一个 awk 版本(你需要一个中继文件,你可以单行)

    awk '/\\phrase/ { p=NR ; } 
         NR == p+3 { gsub("r","ɹ")  ; } 
        {print;} ' old-file.tex > new-file.tex
    

    在哪里

    • /\\phrase/ { p=NR ; }将设置为出现p的每个行号\phrase
    • NR == p+3 { gsub("r","ɹ") ; } 之后在第 3 行执行替换
    • {print;}打印所有行。

    这给了你的样本:(注意ɹeplace)

    \phrase
    {.   .    .     *     *   }
    {I shoul-d've stayed home.}
    {aɪ ʃʊd‿əv ˈsteɪd ˈhoʊm.} <- only ɹeplace on this line
    
    \phrase
    { .   .   *  }
    {Did you eat?}
    {dɪdʒjʊʷˈit? ↗} <- only ɹeplace on this line
    
    \phrase
    { *    .  *    .    *  .  .    .     *   .  }
    {Yeah, I made some pas-ta if you're hun-gry.}
    {ˈjɛə, aɪ ˈmeɪd səm ˈpɑ stəʷɪf jəɹ ˈhʌŋ gɹi.} <- only ɹeplace on this line
    
    • 18
  2. thanasisp
    2022-05-04T11:23:57+08:002022-05-04T11:23:57+08:00
    awk 'c&&!--c {gsub(/r/,"ɹ")} /\\phrase/ {c=3} 1' file > newfile
    

    c&&!--c是一个常见的awk成语,实现while getline逻辑,见参考。

    只有在从 1 减到 0 时,才会执行此条件之后的操作。

    匹配文字'\phrase'时,我们设置c=3了 ,因此gsub()将仅在匹配后的第 3 行执行,并且对所有匹配都重复。

    • 11
  3. Best Answer
    JoL
    2022-05-04T20:46:53+08:002022-05-04T20:46:53+08:00

    既然你在 Emacs 上...

    邪恶/Vim 方式

    如果你已经evil-mode安装(或者你切换到 Vim),你可以这样做:

    :g/^\\phrase/+3s/r/ɹ/g
    

    这是最简单的。

    键盘宏方式

    继续使用 Emacs,您可以使用键盘宏:C-x ( C-M-s ^\\phrase Enter C-n C-n C-n C-a C-space C-e C-M-% r Enter ɹ Enter ! C-x ) C-u 2 C-x e

    C-x (启动宏,C-x )结束宏,C-x e运行宏,C-u 2/C-2修改C-x e使其运行宏 2 次。C-u 10000如果您不想数数,也可以使用大数字。C-M-s搜索正则表达式。向下移动 3 行并选择行后,C-M-%在选择中开始替换。在提示什么替换什么后,!表示接受选择中的所有替换。

    Elisp 方式

    您还可以打开*scratch*缓冲区并运行它(C-M-x同时将光标放在代码上):

    (with-current-buffer "foo"
      (goto-char (point-min))
      (while (re-search-forward "^\\\\phrase" nil t)
        (forward-line 3)
        (replace-string-in-region "r" "ɹ" (point) (line-end-position))))
    

    wherefoo是您要执行此操作的缓冲区的名称。

    编辑:replace-string-in-region在 Emacs 28.1(写作时的最新版本)中引入。如果您的 Emacs 较旧,您可以使用search-forward并replace-match喜欢这样:

    (with-current-buffer "foo"
      (goto-char (point-min))
      (while (re-search-forward "^\\\\phrase" nil t)
        (forward-line 3)
        (while (search-forward "r" (line-end-position) t)
          (replace-match "ɹ"))))
    

    Shell 命令过滤方式

    您还可以通过外部命令过滤 Emacs 缓冲区,就像这里的其他答案之一:C-x h C-u M-| <command> Enter

    C-x h选择整个缓冲区。M-|将提示输入将过滤选择的命令。C-u修改M-|,因此它用输出替换选择,而不是将其放在临时缓冲区中。

    • 9
  4. terdon
    2022-05-04T06:35:03+08:002022-05-04T06:35:03+08:00

    如果您总是在每个部分之间有一个空行,您可以尝试 perl 的“段落”模式将每个部分读为单个“行”:

    $ perl -F'\n' -00ane '$F[3]=~s/r/ɹ/g; print join "\n",@F , "\n"' file 
    \phrase
    {.   .    .     *     *   }
    {I shoul-d've stayed home.}
    {aɪ ʃʊd‿əv ˈsteɪd ˈhoʊm.} <- only ɹeplace on this line
    
    \phrase
    { .   .   *  }
    {Did you eat?}
    {dɪdʒjʊʷˈit? ↗} <- only ɹeplace on this line
    
    \phrase
    { *    .  *    .    *  .  .    .     *   .  }
    {Yeah, I made some pas-ta if you're hun-gry.}
    {ˈjɛə, aɪ ˈmeɪd səm ˈpɑ stəʷɪf jəɹ ˈhʌŋ gɹi.} <- only ɹeplace on this line
    
    

    解释

    • -a: 将每个输入行自动拆分到数组@F中。

    • -F'\n': 在换行符处分割。

    • -00:“段落模式”,行现在由\n\n(空行)定义,因此每个部分都成为“行”。

    • -ne:逐行读取输入文件并将给出的脚本-e应用于每一行。

    • $F[3]=~s/r/ɹ/g;: 全部替换r为ɹ数组的第 4 个元素@F(这是每个部分的第 4 行;数组从 0 开始)。

    • print join "\n",@F , "\n"': 用 加入修改后的@F数组\n,然后将其与额外的\n.


    如果您不能依赖它并且需要在 line matching 之后总是去第三行\phrase,您可以这样做:

    $ perl -pe '$k=0 if /\\phrase\b/; $k++; s/r/ɹ/g if $k==4' file 
    \phrase
    {.   .    .     *     *   }
    {I shoul-d've stayed home.}
    {aɪ ʃʊd‿əv ˈsteɪd ˈhoʊm.} <- only ɹeplace on this line
    
    \phrase
    { .   .   *  }
    {Did you eat?}
    {dɪdʒjʊʷˈit? ↗} <- only ɹeplace on this line
    
    \phrase
    { *    .  *    .    *  .  .    .     *   .  }
    {Yeah, I made some pas-ta if you're hun-gry.}
    {ˈjɛə, aɪ ˈmeɪd səm ˈpɑ stəʷɪf jəɹ ˈhʌŋ gɹi.} <- only ɹeplace on this line
    

    0每次我们看到 时都会设置一个计数器\phrase,并在每一行上将其递增一。然后,我们只在计数器的值为 4 时进行替换。

    • 7
  5. Stéphane Chazelas
    2022-05-04T23:19:27+08:002022-05-04T23:19:27+08:00

    带标准sed:

    sed '/^\\phrase$/{n;n;n;s/r/ɹ/g;}'
    

    y/r/ɹ/代替s/r/ɹ/g也可以在符合 POSIXsed的实现中工作,前提是该ɹ字符在用户的语言环境中被视为一个字符,但 s/r/ɹ/g更便携,因为它也适用于sed不支持多字节字符的实现(如ɹUTF-8 ; 我找不到ɹ在单个字节上编码的任何字符编码)。

    为了ɹ在用户的语言环境中正确编码zsh,您可以这样做:

    sed $'/^\\\\phrase$/{n;n;n;s/r/\u0279/g;}'
    

    在哪里\u0279可以扩展到ɹ 用户语言环境中该字符的编码¹


    ¹$'\uXXXX'其他一些 shell 现在支持这一点,但请注意,在某些情况下,它会在区域设置中扩展,就像在 shell 启动或读取该行代码时一样,不一定sed是在执行该命令的区域设置时. 在 ksh93 中,无论用户的语言环境如何,它总是以 UTF-8 扩展。当该字符在语言环境的字符集中不可用时,shell 之间的行为也会有所不同。它会导致错误zsh

    • 6
  6. hobbs
    2022-05-04T21:42:25+08:002022-05-04T21:42:25+08:00
    perl -Mutf8 -CSD -pe '$phrase = $. if /\\phrase/; s/r/ɹ/g if $. == $phrase + 3'
    

    相当直截了当;$.为 unicode 处理设置标志,如果我们看到,请记住行号 ( ) \phrase,如果行号大于该行号 3,则进行替换。

    • 3
  7. roaima
    2022-05-04T07:14:58+08:002022-05-04T07:14:58+08:00

    由于我们得到了其他答案,因此这是一个几乎重复的问题的有效解决方案。这是针对 GNUsed的,但在链接的答案中也有 POSIX 建议:

    sed '/^\\phrase/,+3 { /^\\phrase/,+2 !{ s/r/ɹ/g } }'
    

    这样做是采用\phrase(bound to start-of-line) 并使用它和接下来的两行 ( +3,从匹配的行作为第一行开始)。对于该组的前两行,它不应用从rto的替换ɹ(这意味着对于该组的最后一行,它确实应用了替换)。

    示例的输出:

    \phrase
    {.   .    .     *     *   }
    {I shoul-d've stayed home.}
    {aɪ ʃʊd‿əv ˈsteɪd ˈhoʊm.} <- only ɹeplace on this line
    
    \phrase
    { .   .   *  }
    {Did you eat?}
    {dɪdʒjʊʷˈit? ↗} <- only ɹeplace on this line
    
    \phrase
    { *    .  *    .    *  .  .    .     *   .  }
    {Yeah, I made some pas-ta if you're hun-gry.}
    {ˈjɛə, aɪ ˈmeɪd səm ˈpɑ stəʷɪf jəɹ ˈhʌŋ gɹi.} <- only ɹeplace on this line
    
    • 2
  8. jubilatious1
    2022-05-06T13:57:51+08:002022-05-06T13:57:51+08:00

    使用Raku(以前称为 Perl_6)

    raku -pe 'state $ph; $ph = 0 if /^ \\phrase $/; s:g/r/ɹ/ if ++$ph == 4;'  
    

    您可能想尝试 Raku,因为它是从头开始构建的以处理 Unicode。上面的代码(实际上)与@hobbs 发布的 Perl5 答案非常相似,因为它使用 Raku 的自动打印逐行-pe命令行标志,并从看到的行开始向下计数\phrase。

    对于上面的代码,变量在程序开始时$ph是stated 一次。由于文件是逐行读取的,因此$ph设置为0当一行包含\phrase但没有遇到任何其他内容时(意思是++$ph== 1 为真)。从这一点开始执行自动递增测试if ++$ph == 4(倒数 3 行),如果满足,则指示替换操作员s:g/r/ɹ/在:global所需行内执行操作。

    • [对于 Perl 爱好者:Raku 摒弃了各种各样的编译器变量,比如$.支持state变量声明器和相关的匿名状态变量,例如$、@和%. 根据文档, “state声明词法范围的变量,就像my。但是,初始化只发生一次......” . Raku 中的$匿名状态变量可用于将行号添加到文本文件,即raku -ne 'put ++$ ~ " $_";']。

    请注意,由于 Raku 可以优雅地处理 Unicode,因此s:g/r/ɹ/可以轻松编写替换:

    s:g/r/\x0279/

    或者

    s:g/r/\c[Latin Small Letter Turned R]/

    ...当您遇到与字体/Unicode 相关的困难时(或者...如果您只是厌倦了尝试记住 Unicode 十六进制代码),上述描述性转换“Latin Small Letter Turned R”可能会有所帮助。

    样本输出:

    \phrase
    {.   .    .     *     *   }
    {I shoul-d've stayed home.}
    {aɪ ʃʊd‿əv ˈsteɪd ˈhoʊm.} <- only ɹeplace on this line
    
    \phrase
    { .   .   *  }
    {Did you eat?}
    {dɪdʒjʊʷˈit? ↗} <- only ɹeplace on this line
    
    \phrase
    { *    .  *    .    *  .  .    .     *   .  }
    {Yeah, I made some pas-ta if you're hun-gry.}
    {ˈjɛə, aɪ ˈmeɪd səm ˈpɑ stəʷɪf jəɹ ˈhʌŋ gɹi.} <- only ɹeplace on this line
    

    https://en.wikipedia.org/wiki/IPA_Extensions
    https://docs.raku.org/syntax/state
    https://raku.org

    • 0

相关问题

  • grep 从 $START 到 $END 的一组行并且在 $MIDDLE 中包含匹配项

  • 重新排列字母并比较两个单词

  • 在awk中的两行之间减去相同的列

  • 多行文件洗牌

  • 如何更改字符大小写(从小到大,反之亦然)?同时[重复]

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