输入
testing on Linux [Remove white space] testing on Linux
输出
testing on Linux [Removewhitespace] testing on Linux
那么,我们如何删除括号之间的所有空白并实现给定的输出呢?
答案1
如果[
,]
是平衡的并且不是嵌套的,您可以使用 GNU,awk
如下所示:
gawk -v RS='[][]' '
NR % 2 == 0 {gsub(/\s/,"")}
{printf "%s", $0 RT}'
即使用[
and]
作为记录分隔符而不是换行符,并仅删除所有其他记录上的空格。
使用 sed,附加要求内部没有换行符[...]
:
sed -e :1 -e 's/\(\[[^]]*\)[[:space:]]/\1/g;t1'
如果它们是平衡的但可能像 in 一样嵌套blah [blih [1] bluh] asd
,那么您可以使用perl
的递归正则表达式运算符,例如:
perl -0777 -pe 's{(\[((?:(?>[^][]+)|(?1))*)\])}{$&=~s/\s//rsg}gse'
另一种可以扩展到非常大的文件的方法是使用(?{...})
perl regexp 运算符来跟踪括号深度,如下所示:
perl -pe 'BEGIN{$/=\8192}s{((?:\[(?{$l++})|\](?{$l--})|[^][\s]+)*)(\s+)}
{"$1".($l>0?"":$2)}gse'
实际上,您也可以一次处理一个字符,如下所示:
perl -pe 'BEGIN{$/=\1}if($l>0&&/\s/){$_=""}elsif($_ eq"["){$l++}elsif($_ eq"]"){$l--}'
该方法可以使用 POSIX 工具来实现:
od -A n -vt u1 |
tr -cs 0-9 '[\n*]' |
awk 'BEGIN{b[32]=""; b[10]=""; b[12]=""} # add more for every blank
!NF{next}; l>0 && $0 in b {next}
$0 == "91" {l++}; $0 == "93" {l--}
{printf "%c", $0}'
使用sed
(假设 内没有换行符[...]
):
sed -e 's/_/_u/g;:1' -e 's/\(\[[^][]*\)\[\([^][]*\)]/\1_o\2_c/g;t1' \
-e :2 -e 's/\(\[[^]]*\)[[:space:]]/\1/g;t2' \
-e 's/_c/]/g;s/_o/[/g;s/_u/_/g'
被考虑空白ASCII 字符集中任何水平(SPC、TAB)或垂直(NL、CR、VT、FF...)间距字符上方。根据您所在的区域设置,其他人可能会被包括在内。
答案2
Perl 5.14 解决方案(更短,在我看来更容易阅读,特别是如果您将其格式化为文件中的多行,而不是单行)
perl -pE 's{(\[ .*? \])}{$1 =~ y/ //dr}gex'
这是可行的,因为在 5.14 中,正则表达式引擎是可重入的。在这里,展开并评论:
s{
(\[ .*? \]) # search for [ ... ] block, capture (as $1)
}{
$1 =~ y/ //dr # delete spaces. you could add in other whitespace here, too
# d = delete; r = return result instead of modifying $1
}gex; # g = global (all [ ... ] blocks), e = replacement is perl code, x = allow extended regex
答案3
Perl解决方案:
perl -pe 's/(\[[^]]*?)\s([^][]*\])/$1$2/ while /\[[^]]*?\s[^][]*\]/'