在 mac 上匹配 sed 中的重复字符
match repeated character in sed on mac
我正在尝试查找 3 个或更多新行的所有实例,并将它们替换为仅 2 个新行(想象一个带有 wayyy 太多白色的文件 space)。我正在使用 sed,但如果更容易的话,可以使用 awk 或类似的答案。
注意:我在 mac 上,所以 sed 与在 linux 上略有不同(BSD vs GNU)
我的实际目标是换行,但我根本无法让它工作,所以为了简单起见,我试图匹配 3 次或更多次重复的 bla
并将其替换为 BLA
.
创建一个名为 stupid.txt 的示例文件:
$ cat stupid.txt
blablabla
$
我的理解是,您使用正则表达式 thing{i,}
.
匹配 i 或更多事物
我试过这个的变体来匹配 3 bla
s 但没有运气:
cat stupid.txt | sed 's/bla{3,}/BLA/g' # simplest way
cat stupid.txt | sed 's/bla\{3,\}/BLA/g' # escape curly brackets
cat stupid.txt | sed -E 's/bla{3,}/BLA/g' # use extended regular expressions
cat stupid.txt | sed -E 's/bla\{3,\}/BLA/g' # use -E and escape brackets
现在我想不出还能尝试什么了!
thing{3,}
匹配 thinggg
。使用 (..)
对事物进行分组,使量词适用于您想要的事物:
$ echo blablabla | sed -E 's/(bla){3}/BLA/g'
BLA
sed -E 's/bla{3,}/BLA/g'
以上匹配 bl
后跟 a
的三个或更多重复。这不是你想要的。看起来您实际上想要 bla
的三个或更多重复。如果是这样,则替换:
$ sed -E 's/bla{3,}/BLA/g' stupid.txt
blablabla
与:
$ sed -E 's/(bla){3,}/BLA/g' stupid.txt
BLA
不过,以上内容并不能直接帮助您完成换行任务,因为默认情况下,sed
一次只读取一行。
替换换行符
让我们考虑这个文件,它在 1
和 2
之间有 3 个换行符:
$ cat file.txt
1
3
要用一个换行符替换任何出现的三个或更多换行符:
$ sed -E 'H;1h;$!d;x; s/\n{3,}/\n/g' file.txt
1
3
工作原理:
H;1h;$!d;x
这一系列复杂的命令会读入整个文件。大概是
最简单的就是将其视为成语。如果你真的想知道
血淋淋的细节:
H
- 追加当前行以保留 space
1h
- 如果这是第一行,覆盖保持 space
有了它
$!d
- 如果这不是最后一行,删除模式 space
并跳转到下一行。
x
- 交换保留和模式 space 以将整个文件放入
模式 space
s/\n{3,}/\n/g
这会将三个或更多换行符的所有序列替换为单个换行符。
备用
上述解决方案一次读入整个文件。对于大(千兆字节)文件,这可能是一个缺点。这种替代方法避免了:
$ sed -E '/^$/{:a; N; /\n$/ba; s/\n{3,}([^\n]*)//}' file.txt # GNU only
1
3
工作原理:
/^$/{...}
这将选择空行。对于空行和只有空行,执行大括号中的命令,它们是:
:a
这定义了一个标签 a
.
N
这会将文件的下一行读入模式 space,与前一行之间用换行符分隔。
/\n$/ba
如果读入的最后一行为空,分支(跳转)到标签a
。
s/\n{3,}([^\n]*)//
如果我们没有分支,则执行此替换,删除多余的换行符。
BSD 版本:我没有 BSD 系统来测试这个,但我猜:
sed -E -e '/^$/{:a' -e N -e '/\n$/ba' -e 's/\n{3,}([^\n]*)//}' file.txt
如果可以接受整个文件:
perl -0777pe 's/(\n){3,}/\n\n/g' newlines.txt
在哪里你应该用任何合适的换行序列替换 \n
。
-0777
告诉 perl 不要将每一行分成自己的记录,这允许跨行工作的正则表达式起作用。
如果您对结果满意,-i
会导致 perl 就地替换文件而不是输出到标准输出:
perl -i -0777pe 's/(\n){3,}/\n\n/g' newlines.txt
您也可以这样做:-i~
创建具有给定后缀的备份文件(在本例中为 ~
)。
如果不能接受整个文件:
perl -ne 'if (/^$/) {$i++}else{$i=0}print if $i<3' newlines.txt
这将打印不是第三个(或更高)连续空行的任何行。 -i
同样适用于此。
ps--MacOS 自带 perl。
要只保留 2 个换行符,你可以试试这个 sed
sed '
/^$/!b
N
/../b
h
:A
y/\n/@/
/^@$/!bB
s/@//
$bB
N
bA
:B
s/^@//
/./ {
x
G
b
}
g
' infile
/^$/!b 如果是空行就不要打印
N 换行
/../b 如果这个新行不为空打印 2 行
h 将 2 个空行保留在保持缓冲区中
:A标签A
此时模式缓冲区中始终有 2 行,第一行是空的
y/\n/@/ 将 \n 替换为 @(您可以选择文件中不存在的其他字符)
/^@$/!bB 如果第二行不为空则跳转到B
s/@// 删除@
$bB 如果是最后一行跳转到B
此时模式中有1个空行space
N 获取最后一行
bA跳转到A
:B标签B
s/^@//去掉行首的@
/./ { 如果最后一行不为空
x 交换模式并保持缓冲区
G 将保持缓冲区添加到模式 space
b跳到结尾
}
g 用 hold space
替换模式 space(空)
打印图案space
我正在尝试查找 3 个或更多新行的所有实例,并将它们替换为仅 2 个新行(想象一个带有 wayyy 太多白色的文件 space)。我正在使用 sed,但如果更容易的话,可以使用 awk 或类似的答案。
注意:我在 mac 上,所以 sed 与在 linux 上略有不同(BSD vs GNU)
我的实际目标是换行,但我根本无法让它工作,所以为了简单起见,我试图匹配 3 次或更多次重复的 bla
并将其替换为 BLA
.
创建一个名为 stupid.txt 的示例文件:
$ cat stupid.txt
blablabla
$
我的理解是,您使用正则表达式 thing{i,}
.
匹配 i 或更多事物
我试过这个的变体来匹配 3 bla
s 但没有运气:
cat stupid.txt | sed 's/bla{3,}/BLA/g' # simplest way
cat stupid.txt | sed 's/bla\{3,\}/BLA/g' # escape curly brackets
cat stupid.txt | sed -E 's/bla{3,}/BLA/g' # use extended regular expressions
cat stupid.txt | sed -E 's/bla\{3,\}/BLA/g' # use -E and escape brackets
现在我想不出还能尝试什么了!
thing{3,}
匹配 thinggg
。使用 (..)
对事物进行分组,使量词适用于您想要的事物:
$ echo blablabla | sed -E 's/(bla){3}/BLA/g'
BLA
sed -E 's/bla{3,}/BLA/g'
以上匹配 bl
后跟 a
的三个或更多重复。这不是你想要的。看起来您实际上想要 bla
的三个或更多重复。如果是这样,则替换:
$ sed -E 's/bla{3,}/BLA/g' stupid.txt
blablabla
与:
$ sed -E 's/(bla){3,}/BLA/g' stupid.txt
BLA
不过,以上内容并不能直接帮助您完成换行任务,因为默认情况下,sed
一次只读取一行。
替换换行符
让我们考虑这个文件,它在 1
和 2
之间有 3 个换行符:
$ cat file.txt
1
3
要用一个换行符替换任何出现的三个或更多换行符:
$ sed -E 'H;1h;$!d;x; s/\n{3,}/\n/g' file.txt
1
3
工作原理:
H;1h;$!d;x
这一系列复杂的命令会读入整个文件。大概是 最简单的就是将其视为成语。如果你真的想知道 血淋淋的细节:
H
- 追加当前行以保留 space1h
- 如果这是第一行,覆盖保持 space 有了它$!d
- 如果这不是最后一行,删除模式 space 并跳转到下一行。x
- 交换保留和模式 space 以将整个文件放入 模式 space
s/\n{3,}/\n/g
这会将三个或更多换行符的所有序列替换为单个换行符。
备用
上述解决方案一次读入整个文件。对于大(千兆字节)文件,这可能是一个缺点。这种替代方法避免了:
$ sed -E '/^$/{:a; N; /\n$/ba; s/\n{3,}([^\n]*)//}' file.txt # GNU only
1
3
工作原理:
/^$/{...}
这将选择空行。对于空行和只有空行,执行大括号中的命令,它们是:
:a
这定义了一个标签
a
.N
这会将文件的下一行读入模式 space,与前一行之间用换行符分隔。
/\n$/ba
如果读入的最后一行为空,分支(跳转)到标签
a
。s/\n{3,}([^\n]*)//
如果我们没有分支,则执行此替换,删除多余的换行符。
BSD 版本:我没有 BSD 系统来测试这个,但我猜:
sed -E -e '/^$/{:a' -e N -e '/\n$/ba' -e 's/\n{3,}([^\n]*)//}' file.txt
如果可以接受整个文件:
perl -0777pe 's/(\n){3,}/\n\n/g' newlines.txt
在哪里你应该用任何合适的换行序列替换 \n
。
-0777
告诉 perl 不要将每一行分成自己的记录,这允许跨行工作的正则表达式起作用。
如果您对结果满意,-i
会导致 perl 就地替换文件而不是输出到标准输出:
perl -i -0777pe 's/(\n){3,}/\n\n/g' newlines.txt
您也可以这样做:-i~
创建具有给定后缀的备份文件(在本例中为 ~
)。
如果不能接受整个文件:
perl -ne 'if (/^$/) {$i++}else{$i=0}print if $i<3' newlines.txt
这将打印不是第三个(或更高)连续空行的任何行。 -i
同样适用于此。
ps--MacOS 自带 perl。
要只保留 2 个换行符,你可以试试这个 sed
sed '
/^$/!b
N
/../b
h
:A
y/\n/@/
/^@$/!bB
s/@//
$bB
N
bA
:B
s/^@//
/./ {
x
G
b
}
g
' infile
/^$/!b 如果是空行就不要打印
N 换行
/../b 如果这个新行不为空打印 2 行
h 将 2 个空行保留在保持缓冲区中
:A标签A
此时模式缓冲区中始终有 2 行,第一行是空的
y/\n/@/ 将 \n 替换为 @(您可以选择文件中不存在的其他字符)
/^@$/!bB 如果第二行不为空则跳转到B
s/@// 删除@
$bB 如果是最后一行跳转到B
此时模式中有1个空行space
N 获取最后一行
bA跳转到A
:B标签B
s/^@//去掉行首的@
/./ { 如果最后一行不为空
x 交换模式并保持缓冲区
G 将保持缓冲区添加到模式 space
b跳到结尾
}
g 用 hold space
替换模式 space(空)打印图案space