我有一个大文件,其中包含数百个以下形式的英语短语:
\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
。谢谢你!
答案1
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
答案2
awk 'c&&!--c {gsub(/r/,"ɹ")} /\\phrase/ {c=3} 1' file > newfile
c&&!--c
是一个常见的awk
习惯用法,实现while
getline
逻辑,请参见参考。
仅当从 1 减到 0 时才会执行此条件后的操作。
当匹配文字时'\phrase'
,我们设置c=3
,因此gsub()
只会在匹配后的第三行执行,并且这对所有匹配都重复。
答案3
既然你使用的是 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-%
开始选择替换。提示什么替换什么后,!
表示接受选择中的所有替换。
埃利普之路
您还可以打开*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))))
其中foo
是您要执行此操作的缓冲区的名称。
编辑: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-|
,以便用输出替换选择,而不是将其放入临时缓冲区中。
答案4
与标准sed
:
sed '/^\\phrase$/{n;n;n;s/r/ɹ/g;}'
y/r/ɹ/
代替s/r/ɹ/g
也可以在 POSIX 兼容的sed
实现中工作,只要该ɹ
字符被视为用户区域设置中的字符,但 s/r/ɹ/g
会更便携,因为它也可以与sed
不支持多字节字符的实现一起工作(如ɹ
UTF-8 中的情况) ;我找不到任何ɹ
在单个字节上编码的字符编码)。
为了ɹ
在用户的区域设置中正确编码,zsh
您可以这样做:
sed $'/^\\\\phrase$/{n;n;n;s/r/\u0279/g;}'
它将扩展到 用户区域设置中\u0279
该字符的编码ɹ
¹$'\uXXXX'
现在,其他一些 shell 也支持这一点,但请注意,在某些 shell 中,它会在语言环境中展开,因为它是在 shell 启动时或读取该行代码时进行的,而不一定是在执行该sed
命令的语言环境中进行的。在 ksh93 中,无论用户的区域设置如何,它始终以 UTF-8 扩展。当该字符在区域设置的字符集中不可用时,不同 shell 的行为也会有所不同。它会导致错误zsh