-1

An interview question I read:

Let's say you're on my team, and I've decided I'm a real stickler for code formatting. But I've got peculiar tastes, and one day I decide I want to have all parentheses stand out very clearly in your code.

So let's say you've got a set of source files in C, C++, or Java. Your choice. And I want you to modify them so that in each source file, every open- and close-parenthesis has exactly one space character before and after it. If there is any other whitespace around the parenthesis, it's collapsed into a single space character.

For instance, this code:

foo (bar ( new Point(x, graph.getY()) ));

Would be modified to look like this:

foo ( bar ( new Point ( x, graph.getY ( ) ) ) );

How to do this with sed ?

EDIT
my approach

sed -Ee 's/([()])([()])([()])/\1 \2 \3 /g' -e 's/([ ]{1,}|^|([0-9a-zA-Z()]))([()])([ ]{1,}|$|([0-9;a-z()]))/\2 \3 \5/g'  filename.c 

This fails at cases like func(a); my code outputs it as func ( a);

Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
  • 2
    This interview question shows the ignorance of the interviewer. REs cannot balance parentheses or count characters (like `"`, so as to know if you are inside or outside a C string for example), so you would end up changing spaces around parentheses also inside strings. If you use RE to accomplish this task you are bound to fail. – fferri Jun 25 '15 at 05:55
  • 1
    @mescalinum assume that parenthesis are absent in a C string then how do we solve this and how pass cases where my code fails – Dhruv Raj Singh Rathore Jun 25 '15 at 05:58
  • 1
    Of course they can ever since introduction of [recursion](http://www.regular-expressions.info/recurse.html) and [balanced groups](http://www.regular-expressions.info/balancing.html). – rr- Jun 25 '15 at 07:33
  • then how would you check if a parenthesis is inside a c string " (" or '(' – Dhruv Raj Singh Rathore Jun 25 '15 at 07:35
  • [Here is a good start.](http://stackoverflow.com/a/14952740/2016221) note that sed is centuries behind PCRE so you'll need perl or something similar. – rr- Jun 25 '15 at 07:41

3 Answers3

2

Updated: You need to reduce leading and trailing spaces to exactly one independently of each other:

$ cat par.sed
s/[[:space:]]*\([()]\)/ \1/g
s/\([()]\)[[:space:]]*/\1 /g
$ sed -i.bak -f par.sed filename.c

Easier to understand script:

# Collapse leading spaces:
s/ *(/ (/g
s/ *)/ )/g
# Collapse trailing spaces:
s/( */( /g
s/) */) /g
chw21
  • 7,970
  • 1
  • 16
  • 31
  • your code creates two spaces in the given test case (__)__)__)__) – Dhruv Raj Singh Rathore Jun 25 '15 at 06:27
  • I just noticed another thing: My example is now correct as to the quoted assignment, but will not be correct as to your example: In your example output there is no space between the last closing parenthesis and the semicolon. But I don't see such a restriction in the assignment, and I haven't implemented it. – chw21 Jun 26 '15 at 00:14
1
sed -e "/[\"']/ b" -e '
s/[[:blank:]]*\([()]\)[[:blank:]]*/ \1 /g
:cycle
s/\([()]\)[[:blank:]]\{2,\}\([()]\)/\1 \2/g;t cycle
s/) ;/);/' YourFile
  • first test to skip line with " or ', a bit harder (long code) to treat (optional)
  • treat the special ; after a )
  • use of class blank and not space for use of tab ansd space char only and not other case like NL, FF, VT, CR (normaly not necessary because we treat here 1 line a t a time but in c, you could have instruction on several line, so if you want to extend )

Adaptation for space inbetween (thanks to @User112638726 for this remark)

NeronLeVelu
  • 9,908
  • 1
  • 23
  • 43
  • This leaves multiple blanks inbetweeen adjacent brackets – 123 Jun 25 '15 at 07:23
  • @User112638726 right, forget the `g` occur only to next occurence so one change/pattern is excluded from following search. Code adapted for this – NeronLeVelu Jun 25 '15 at 08:43
0

Let's try

echo "foo (bar ( new Point(x, graph.getY()) ));" | sed -r 's/([^ ])\(/\1 \(/g; s/([^ ])\)/\1 \)/g; s/\(([^ ])/\( \1/g; s/\)([^ ])/\) \1/g'  

output
foo ( bar ( new Point ( x, graph.getY ( ) ) ) ) ;

josifoski
  • 1,696
  • 1
  • 14
  • 19