Using Raku (formerly known as Perl_6)
~$ raku -pe 's/^ [\d+ " "?] \t* \H+? <(" " ** 2..*)> / /;' file
#OR
~$ raku -pe 's/^ [\d+ " "?] \c[TAB]* \H+? <(\c[SPACE] ** 2..*)> / /;' file
The Raku code above quite literally differentiates between tabs (\t
or \c[TAB]
and spaces (" "
or \c[SPACE]
).
The -pe
flags run code linewise over the input, with autoprinting. The regex searches from the ^
beginning-of-the-string for [\d+ " "?]
digits followed by 0-or-1 space, followed by an optional tab, followed (non-greedily) by \H+?
one-or-more non-horizontal-whitespace characters, followed by 2..*
two-or-more spaces. The <(
...)>
capture markers drop everything from the match except the final two-or-more spaces, which are replaced with a single space.
Omit the bracketed [\d+ " "?]
group if no line numbers. Only one substitution per line, so may have to be run multiple times if multiple spaced characters at the right end of the line.
Sample Input:
1 /**
2 a\tb\tc
3 **/
4 int main() {
5\tint x;
6\tif ( condition) {
7\treturn x;
8\t}
9 }
Sample Output:
1 /**
2 a\tb\tc
3 **/
4 int main() {
5\tint x;
6\tif ( condition) {
7\treturn x;
8\t}
9 }
Of course, the answer above is predicated upon characters-within-comment-blocks being separated by tabs, instead of multiple-spaces. Maybe the best way to ensure that is to pre-run a substitution for comment blocks specifically:
~$ raku -pe 'state $ph; \
$ph = 1 if /^ "/**" \s* $/; \
$ph = 0 if /^ "**/" \s* $/; \
s:g/" " ** 4/\t/ if $ph == 1 ;' file
The code above will substitute one tab for every 4 spaces, only within comment blocks. Add back in the bracketed [\d+ " "?]
group just after the ^
in the second and third statements, if each line starts with a line-number.
https://unix.stackexchange.com/a/701572/227738
https://docs.raku.org/language/regexes
https://raku.org
printf("some spacey words\n");
where the words have more than one space between them? (the markup here removes the multiple spaces between the words).indent
orclang-format
.