我如何用 sed 交换行的剩余部分(第一个字符除外)?

我如何用 sed 交换行的剩余部分(第一个字符除外)?

我有一个文件,fr.fc代表使用的抽认卡硬盘我想用它来生成sed类似的文件,fr-swapped.fc

%% This is a card set for hardv(1)
%% Created at Feb 1, 1997
NEXT    2023-09-10 09:18:28 +0200
PREV    2023-09-08 09:18:28 +0200
Q   We should save money.
A   Nous devons économiser de l'argent.
%%
NEXT    2023-09-09 10:51:14 +0200
PREV    2023-09-05 10:51:14 +0200
Q   I should save money.
A   Je dois économiser de l'argent.
%%
%%
NEXT    2023-09-08 20:50:03 +0200
PREV    2023-09-08 20:50:03 +0200
Q   Demander son chemin in four ways de quatre manières.
A   Pardon, pouvez-vous m'aider ...
%%
%%
NEXT    2023-09-08 20:50:03 +0200
PREV    2023-09-08 20:50:03 +0200
Q   I need your help.
A   Je besoin de votre aide.
%%
%%

我想将问题(以 开头^Q\t)与答案(以 开头^A\t)交换,而不交换Q它们A本身,以便结果看起来像这样。为了简单起见,我们假设答案和问题都只有一行长度。NEXT和之后PREV也是选项卡。答案或问题中间的任何分隔符都是空格 - 此处不允许使用表格。

%%
%%
NEXT    2023-09-08 20:50:03 +0200
PREV    2023-09-08 20:50:03 +0200
Q   Je besoin de votre aide.
A   I need your help.
%%
%%

我尝试过sed -n -E '/^Q\t/p; /^A\t/p' fr.fc | sed -E 'N; s/^([QA]{1,1})(.*)\n(.*)/\3\n\2/' >fr-swapped.fc但没有成功。

答案1

惰性方法将在 slurp 模式下使用perl,其中加载整个输入$_,您可以对其进行替换:

perl -0777 -pe 's/^Q(\t.*\n)A(\t.*\n)/Q$2A$1/mg' your-file

如果像您问题的早期版本一样,Qs 和As 可以由使用 TAB 缩进行继续的几行组成,那么很容易适应:

perl -0777 -pe 's/^Q(\t.*\n(?:\t.*\n)*)A(\t.*\n(?:\t.*\n)*)/Q$2A$1/mg' your-file

顺便说一句,应该是We should-> Nous devrionsI should-> Je devraisI need-> J'ai besoin de

答案2

为什么这么复杂?您可以将N;P;D模式与 any 一起使用sed,以始终同时处理两行,如下所示:

sed -E 'N;s/^Q(.*)(\nA)(.*)/Q\3\2A\1/;P;D'

它完全按照您的描述进行操作:将双线分成 Q 之后的所有内容和 A 之后的所有内容,然后交换这些部分。

答案3

使用GNUsed

$ sed -Ez 's/(Q[ \t]+)([^\n]*\n?)(A[ \t]+)([^\n]*\n?)/\1\4\3\2/gwfr-swapped.fc' fr.fc
$ cat fr-swapped.fc
%% This is a card set for hardv(1)
%% Created at Feb 1, 1997
NEXT    2023-09-10 09:18:28 +0200
PREV    2023-09-08 09:18:28 +0200
Q   Nous devons économiser de l'argent.
A   We should save money.
%%
NEXT    2023-09-09 10:51:14 +0200
PREV    2023-09-05 10:51:14 +0200
Q   Je dois économiser de l'argent.
A   I should save money.
%%
%%
NEXT    2023-09-08 20:50:03 +0200
PREV    2023-09-08 20:50:03 +0200
Q   Pardon, pouvez-vous m'aider ...
A   Demander son chemin in four ways de quatre manières.
%%
%%
NEXT    2023-09-08 20:50:03 +0200
PREV    2023-09-08 20:50:03 +0200
Q   Je besoin de votre aide.
A   I need your help.
%%
%%

答案4

这可能是您想要使用任何 awk 执行的操作:

$ cat tst.sh
#!/usr/bin/env bash

awk '
    sub(/^Q\t/,"A\t") {
        question = $0
        next
    }
    sub(/^A\t/,"Q\t") {
        $0 = $0 ORS question
    }
    { print }
' fr.fc

$ ./tst.sh
%%      This is a card set for hardv(1)
%%      Created at Feb 1, 1997
NEXT    2023-09-10 09:18:28 +0200
PREV    2023-09-08 09:18:28 +0200
Q       Nous devons économiser de l'argent.
A       We should save money.
%%
NEXT    2023-09-09 10:51:14 +0200
PREV    2023-09-05 10:51:14 +0200
Q       Je dois économiser de l'argent.
A       I should save money.
%%
%%
NEXT    2023-09-08 20:50:03 +0200
PREV    2023-09-08 20:50:03 +0200
Q       Pardon, pouvez-vous m'aider ...
A       Demander son chemin in four ways de quatre manières.
%%
%%
NEXT    2023-09-08 20:50:03 +0200
PREV    2023-09-08 20:50:03 +0200
Q       Je besoin de votre aide.
A       I need your help.
%%
%%

如果您更看重清晰性,那么上面的内容就像 sed 一样简洁:

$ awk 'sub(/^Q\t/,"A\t"){q=$0;next}sub(/^A\t/,"Q\t"){$0=$0ORS q}1' fr.fc
%%      This is a card set for hardv(1)
%%      Created at Feb 1, 1997
NEXT    2023-09-10 09:18:28 +0200
PREV    2023-09-08 09:18:28 +0200
Q       Nous devons économiser de l'argent.
A       We should save money.
%%
NEXT    2023-09-09 10:51:14 +0200
PREV    2023-09-05 10:51:14 +0200
Q       Je dois économiser de l'argent.
A       I should save money.
%%
%%
NEXT    2023-09-08 20:50:03 +0200
PREV    2023-09-08 20:50:03 +0200
Q       Pardon, pouvez-vous m'aider ...
A       Demander son chemin in four ways de quatre manières.
%%
%%
NEXT    2023-09-08 20:50:03 +0200
PREV    2023-09-08 20:50:03 +0200
Q       Je besoin de votre aide.
A       I need your help.
%%
%%

根据上面评论中我的问题的答案,可能会有更好的解决方案。

相关内容