Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to split a string by commas positioned outside of parenthesis?

Tags:

I got a string of such format:

"Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)" 

so basicly it's list of actor's names (optionally followed by their role in parenthesis). The role itself can contain comma (actor's name can not, I strongly hope so).

My goal is to split this string into a list of pairs - (actor name, actor role).

One obvious solution would be to go through each character, check for occurances of '(', ')' and ',' and split it whenever a comma outside occures. But this seems a bit heavy...

I was thinking about spliting it using a regexp: first split the string by parenthesis:

import re x = "Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)" s = re.split(r'[()]', x)  # ['Wilbur Smith ', 'Billy, son of John', ', Eddie Murphy ', 'John', ', Elvis Presley, Jane Doe ', 'Jane Doe', ''] 

The odd elements here are actor names, even are the roles. Then I could split the names by commas and somehow extract the name-role pairs. But this seems even worse then my 1st approach.

Are there any easier / nicer ways to do this, either with a single regexp or a nice piece of code?

like image 775
kender Avatar asked Oct 30 '09 08:10

kender


People also ask

How do you split a string with comma separated?

To split a string with comma, use the split() method in Java. str. split("[,]", 0); The following is the complete example.

How do you split a string with dots Python?

String split example s = "Python string example. We split it using the dot character." parts = s. split(".")


2 Answers

s = re.split(r',\s*(?=[^)]*(?:\(|$))', x)  

The lookahead matches everything up to the next open-parenthesis or to the end of the string, iff there's no close-parenthesis in between. That ensures that the comma is not inside a set of parentheses.

like image 44
Alan Moore Avatar answered Oct 29 '22 10:10

Alan Moore


One way to do it is to use findall with a regex that greedily matches things that can go between separators. eg:

>>> s = "Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)" >>> r = re.compile(r'(?:[^,(]|\([^)]*\))+') >>> r.findall(s) ['Wilbur Smith (Billy, son of John)', ' Eddie Murphy (John)', ' Elvis Presley', ' Jane Doe (Jane Doe)'] 

The regex above matches one or more:

  • non-comma, non-open-paren characters
  • strings that start with an open paren, contain 0 or more non-close-parens, and then a close paren

One quirk about this approach is that adjacent separators are treated as a single separator. That is, you won't see an empty string. That may be a bug or a feature depending on your use-case.

Also note that regexes are not suitable for cases where nesting is a possibility. So for example, this would split incorrectly:

"Wilbur Smith (son of John (Johnny, son of James), aka Billy), Eddie Murphy (John)" 

If you need to deal with nesting your best bet would be to partition the string into parens, commas, and everthing else (essentially tokenizing it -- this part could still be done with regexes) and then walk through those tokens reassembling the fields, keeping track of your nesting level as you go (this keeping track of the nesting level is what regexes are incapable of doing on their own).

like image 171
Laurence Gonsalves Avatar answered Oct 29 '22 10:10

Laurence Gonsalves