Eu tenho um arquivo grande que contém centenas de frases em inglês no seguinte formato:
\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
É um arquivo LaTeX .tex
. Eu gostaria de substituir todos os r
caracteres em cada transcrição fonética (por transcrição fonética quero dizer cada terceira linha após a \phrase
linha) pelo ɹ
símbolo (código hexadecimal U+0279
).
Fazer isso manualmente no Emacs é complicado para mim. Eu queria saber se existe uma maneira de direcionar essas linhas de alguma forma e fazer a substituição automaticamente.
Todos os r
caracteres devem ser substituídos por ɹ
, não há exceção, mas apenas na transcrição fonética, deixe r
como está no texto em inglês/não fonético.
É possível fazer isso de alguma forma usando um script ou algo assim? Não há quebras de linha no meu documento, então a transcrição é sempre a terceira linha após \phrase
. Obrigada!
uma versão awk (você precisará de um arquivo de retransmissão, você pode colocá-lo em uma linha)
Onde
/\\phrase/ { p=NR ; }
será definidop
para cada número de linha onde\phrase
aparecerNR == p+3 { gsub("r","ɹ") ; }
realizar a substituição na 3ª linha após{print;}
imprimir toda a linha.isso deu em sua amostra: (observe o
ɹeplace
)c&&!--c
é umawk
idioma comum, implementando awhile
getline
lógica, consulte a referência .A ação que segue esta condição será executada somente ao diminuir de um para zero.
Ao combinar um literal
'\phrase'
, definimosc=3
, paragsub()
que seja executado apenas na 3ª linha após a correspondência, e isso se repete para todas as correspondências.Já que você está no Emacs...
O Caminho do Mal/Vim
Se você
evil-mode
instalou (ou mudou para o Vim), pode fazer isso:Isso é o mais simples.
A maneira macro do teclado
Ficando com o estoque do Emacs, você pode usar uma macro de teclado:
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 (
inicia a macro,C-x )
finaliza a macro,C-x e
executa a macro,C-u 2
/C-2
modificaC-x e
para que execute a macro 2 vezes. Você também pode usar um número grande comoC-u 10000
se não quiser contar.C-M-s
procura uma regex. Após descer 3 linhas e selecionar a linha,C-M-%
inicia uma substituição na seleção. Após os prompts para o que substitui o quê,!
significa aceitar todas as substituições na seleção.O Caminho da Elisp
Você também pode abrir o
*scratch*
buffer e executá-lo (comC-M-x
o cursor no código):onde
foo
é o nome do buffer onde você deseja fazer isso.EDIT:
replace-string-in-region
foi introduzido no Emacs 28.1 (versão mais recente até o momento da escrita). Se o seu Emacs for mais antigo, você pode usarsearch-forward
ereplace-match
assim:A maneira do filtro de comandos do Shell
Você também pode filtrar o buffer do Emacs por meio de um comando externo, como uma das outras respostas aqui:
C-x h C-u M-| <command> Enter
C-x h
seleciona todo o buffer.M-|
solicitará o comando que filtrará a seleção.C-u
modificaM-|
para substituir a seleção pela saída em vez de colocá-la em um buffer temporário.Se você sempre tem uma linha em branco entre cada seção, você pode tentar o modo "parágrafo" do perl para ler cada seção como uma única "linha":
Explicação
-a
: divide automaticamente cada linha de entrada no array@F
.-F'\n'
: dividido em caracteres de nova linha.-00
: "modo de parágrafo", as linhas agora são definidas por\n\n
(uma linha vazia), então cada seção se torna uma "linha".-ne
: leia o arquivo de entrada linha por linha e aplique o script fornecido por-e
a cada linha.$F[3]=~s/r/ɹ/g;
: substitua allr
porɹ
no 4º elemento do array@F
(esta é a 4ª linha de cada seção; arrays começam em 0).print join "\n",@F , "\n"'
: junte o@F
array modificado com\n
e imprima-o junto com um extra\n
.Se você não pode confiar nisso e precisa sempre ir para a 3ª linha após uma correspondência de linha
\phrase
, você pode fazer:Isso define um contador para
0
cada vez que vemos\phrase
, e o incrementa em um em cada nova linha. Então, só fazemos a substituição quando o valor do contador for 4.Com padrão
sed
:y/r/ɹ/
no lugar des/r/ɹ/g
também funcionaria em implementações compatíveis com POSIXsed
desde que oɹ
caractere seja considerado como um na localidade do usuário, mass/r/ɹ/g
seria mais portátil, pois também funcionaria comsed
implementações que não suportam caracteres multi-byte (comoɹ
em UTF-8 ; Não consigo encontrar nenhuma codificação de caracteres ondeɹ
esteja codificado em um único byte).Para que isso
ɹ
seja codificado corretamente na localidade do usuário, comzsh
, você pode fazer:Onde isso
\u0279
seria expandido para a codificação desseɹ
caractere na localidade do usuário¹¹ Isso
$'\uXXXX'
agora é suportado por alguns outros shells, mas cuidado com o fato de que em alguns, isso é expandido na localidade como era quando o shell foi iniciado ou quando essa linha de código foi lida, não necessariamente quando a localidade em que essesed
comando é executado . No ksh93, é sempre expandido em UTF-8, independentemente da localidade do usuário. Quando o caractere não está disponível no charset da localidade, o comportamento também varia entre os shells. Causa um erro dezsh
bastante direto; defina sinalizadores para manipulação de unicode, lembre-se do número da linha (
$.
) se virmos\phrase
, e faça uma substituição se o número da linha for três maior que isso.Como estamos obtendo outras respostas, aqui está uma solução trabalhada de uma pergunta quase duplicada . Isso é para GNU
sed
, mas na resposta vinculada também há sugestões POSIX:O que isso faz é pegar o
\phrase
(limitado ao início da linha) e trabalhar com isso e as próximas duas linhas (+3
, começando com a linha correspondente como linha um). Para as duas primeiras linhas deste grupo não aplica a substituição der
paraɹ
(a implicação é que para a última linha do grupo aplica a substituição).Saída do exemplo:
Usando Raku (anteriormente conhecido como Perl_6)
Você pode querer experimentar o Raku, já que ele foi construído desde o início para lidar com Unicode. O código acima (na verdade) é muito semelhante à resposta Perl5 postada por @hobbs, na medida em que usa os
-pe
sinalizadores de linha de comando de impressão automática do Raku e conta as linhas a partir da linha em que\phrase
é visto.Para o código acima, a variável
$ph
éstate
d uma vez no início do programa. À medida que o arquivo é lido na linha,$ph
é definido para0
quando uma linha contendo\phrase
e nada mais é encontrada (significado++$ph
== 1 é True). A partir deste ponto é realizado um teste deif ++$ph == 4
autoincremento (contagem regressiva de 3 linhas), que se satisfeito, então direciona o operador de substituiçãos:g/r/ɹ/
para atuar:global
ly dentro da linha desejada.$.
em favor dostate
declarador de variáveis e variáveis de estado anônimas associadas, como$
,@
, e%
. De acordo com os documentos, "state
declara variáveis com escopo léxico, assim comomy
. No entanto, a inicialização acontece exatamente uma vez...". . A$
variável de estado anônima no Raku pode ser usada para adicionar números de linha a um arquivo de texto, ou seja,raku -ne 'put ++$ ~ " $_";'
].Observe que, como o Raku lida com o Unicode normalmente, a
s:g/r/ɹ/
substituição pode ser escrita com a mesma facilidade:s:g/r/\x0279/
OU
s:g/r/\c[Latin Small Letter Turned R]/
...a conversão descritiva acima "Latin Small Letter Turned R" pode ajudar quando você tiver dificuldades relacionadas a fontes/Unicode (ou... se você estiver cansado de tentar lembrar de códigos hexadecimais Unicode ).
Saída de amostra:
https://en.wikipedia.org/wiki/IPA_Extensions
https://docs.raku.org/syntax/state
https://raku.org