sed:删除字符串之间的多余空格到单个空格,同时保持前导选项卡完好无损

sed:删除字符串之间的多余空格到单个空格,同时保持前导选项卡完好无损

我有一个代码:

1 /**             
2 a        b         c
3 **/
4 int main() {
5     int x;
6     if ( condition) {
7     return       x;
8     }
9 }

我需要将标记或字符串之间的多个空格更改为单个空格,例如在第 7 行中,但注释(第 2 行)不应受到影响,代码中的前导选项卡也不应受到影响。所以,输出应该是:

1 /**             
2 a        b         c
3 **/
4 int main() {
5     int x;
6     if ( condition) {
7     return x;
8     }
9 }

我尝试使用 'tr':~$ tr -s " " < file但它更改了第 2 行,并删除了第 5 行至第 8 行中的前导制表符。可以使用 来完成吗sed

答案1

会走多远

sed -rn '\#/\*\*#,\#\*\/*# {p;b}; s/([^ ]) +/\1 /g; p' file

我懂了?它打印未修改的注释行(但不能处理同一行中的注释打开/关闭)并跳过脚本的其余部分。对于未注释的行,它将非空格字符后面的任何多个空格(因此行缩进超出范围)压缩为单个空格。

答案2

最后,这对我有用:

sed -i 's/\([a-zA-Z]\+\)\( *\)\([a-zA-Z]\+\)/\1 \3/g' $1

答案3

使用(以前称为 Perl_6)

~$ raku -pe 's/^ [\d+ " "?] \t* \H+? <(" " ** 2..*)> / /;'  file

#OR

~$ raku -pe 's/^ [\d+ " "?] \c[TAB]* \H+? <(\c[SPACE] ** 2..*)> / /;'  file

上面的 Raku 代码从字面上区分了制表符(\t或)\c[TAB]和空格(" "\c[SPACE])。

这些-pe标志在输入上逐行运行代码,并具有自动打印功能。正则表达式从^字符串的开头搜索[\d+ " "?]数字,后跟 0 或 1 空格,后跟可选制表符,后跟(非贪婪地)\H+?一个或多个非水平空白字符,最后是 2..*两个或多个空格。<(...捕获)>标记会删除匹配中的所有内容,除了最后两个或更多空格,这些空格将替换为单个空格。

[\d+ " "?]如果没有行号,则省略括号内的组。每行只有一次替换,因此如果行右端有多个空格字符,则可能需要运行多次。

输入示例:

1 /**             
2 a\tb\tc
3 **/
4 int main() {
5\tint x;
6\tif ( condition) {
7\treturn       x;
8\t}
9 }

示例输出:

1 /** 
2 a\tb\tc
3 **/
4 int main() {
5\tint x;
6\tif ( condition) {
7\treturn x;
8\t}
9 }

当然,上面的答案是基于注释块中的字符由制表符分隔,而不是多个空格。也许是确保的最好方法是为了预运行具体替换注释块:

~$ raku -pe 'state $ph;                     \
             $ph = 1 if /^  "/**"  \s* $/;  \
             $ph = 0 if /^  "**/"  \s* $/;  \
             s:g/" " ** 4/\t/ if  $ph == 1 ;'   file

上面的代码将每 4 个空格替换一个制表符,仅限在注释块内。如果每行都以行号开头,[\d+ " "?]则添加回第二个和第三个语句中的括号组中。^

https://unix.stackexchange.com/a/701572/227738
https://docs.raku.org/language/regexes
https://raku.org

相关内容