Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sed regex to extract selector from method declaration (Obj-C)

I'm converting an Objective-C method declaration to its selector, i.e. removing the parameter names and types like for this NSString method:

- (void)getCString:(char *)buffer maxLength:(NSUInteger)maxLength

to get

getCString:maxLength:

So I've figured out that the regular expression \w*?\: will extract what I need (works fine in an online regex-checker like http://gskinner.com/RegExr/) but I just can't get sed (on OS X) to work with the regular expression to extract the signature.

From various sed snippet/sample pages I've got the impression that something like this should work, except it doesn't (nor the ~250 variations I've tried...):

 cat test.m | sed '/\w*?\:/p'

Can any sed wizard give a hand?

like image 461
Jay Avatar asked Oct 19 '25 01:10

Jay


1 Answers

You're trying to extract the method selector, not the method signature. The method signature includes the return type and argument types. The method selector includes only the keywords and colons.

You can tell sed to use POSIX extended regular expressions using the non-standard -E flag.

This might do what you want:

sed -E -n '/^[-+]/{
    s/^.[[:blank:]]*(\([^)]*\))?[[:blank:]]*//
    s/[[:blank:]]*[;{][[:blank:]]*$//
    s/:[^:]*([[:blank:]]|$)/:/g
    p
}' test.m

That's a rather complicated sed command for a beginner, so let's break it down.

  1. The -E flag enables extended regular expressions on FreeBSD derivatives like Mac OS X.

  2. The -n flag tells sed not to print every input line automatically.

  3. /^[-+]/ selects every line that starts with a - (for an instance method) or a + (for a class method).

  4. { begins a group of sed commands, which will all be executed on each selected line. The group ends at the matching }.

  5. s/^.[[:blank:]]*(\([^)]*\))?[[:blank:]]*// removes the - or +, followed by any amount of whitespace, followed by the return type of the method, followed by any amount of whitespace. It removes the return type by matching a ( followed by any number of non-) characters followed by a ). Note that the return type is actually optional; a method declared - foo:(int)x; is perfectly valid (and has a default return type of id). Also note that this regular expression won't work properly if your method's return type is an explicit function pointer or block, like - (void (^)(void))getBlock;, because you cannot handle nested parentheses with a regular expression.

  6. s/[[:blank:]]*[;{][[:blank:]]*$// removes the ; or {, and any surrounding whitespace, from the end of the line. This is important to make the next command work properly.

  7. s/:[^:]*([[:blank:]]|$)/:/g matches a colon, followed by as many non-: characters as possible, followed by either whitespace or end-of-line, and replaces the match with just a colon. The trailing g flag tells sed to do this for every match on the line. This command removes argument types and names. Note that this command will properly handle nested parentheses, unlike the command that removes the return type. Also note that argument types are also optional; - foo:bar is a method that takes one argument (whose type defaults to id).

Example:

:; echo '- (void)getCString:(char *)buffer maxLength:(NSUInteger)maxLength' | sed -E -n '/^[-+]/{
    s/^.[[:blank:]]*(\([^)]*\))?[[:blank:]]*//
    s/[[:blank:]]*[;{][[:blank:]]*$//
    s/:[^:]*([[:blank:]]|$)/:/g
    p
}'
getCString:maxLength:

Note that this sed command will also work for methods that have no arguments, like - (void)save;.

like image 187
rob mayoff Avatar answered Oct 20 '25 16:10

rob mayoff



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!