0

If I've a string like, 'level1-4car10', I want to extract all those numbers (integers, specifically) as numbers, in a list.

When I run,

re.split(r'(\d+)', 'level1-4car10')

That does half the job, giving me a result of,

['level', '1', '-', '4', 'car', '10', '']

But what I'm looking for is,

['level', 1, '-', 4, 'car', 10, '']

The 1, 4 and 10 are real integers now, not numbers. Currently, using re.split with capturing, I'll have to run through the returned list to do that, and I'm just wondering if there's any other option available to me to do this in a more one-pass way, like the key section of sorted.

edit: I've reworded the question, specifically stating single pass.

This is also different to the answer regarding Python: Extract numbers from a string as I don't just want the numbers, I want the numbers and the not number in a list ordered by how they appear in the sentence.

Community
  • 1
  • 1
seaders
  • 3,878
  • 3
  • 40
  • 64
  • *I want to **extract** all those numbers* why use re.split then? now you're just splitting the string on numbers – Tim Jun 23 '15 at 12:08
  • I found that was the easiest way to split the string and end up with what closest to what I wanted first pass. I'm more than happy to be corrected and pointed away from `re.split`. – seaders Jun 23 '15 at 12:09
  • See also: http://stackoverflow.com/questions/4289331/python-extract-numbers-from-a-string – Tim Jun 23 '15 at 12:14
  • Are you still expecting other answers?..because I see you didn't select the accepted one. – Iron Fist Jun 24 '15 at 00:16
  • @TimCastelijns, the title is operating on all outputs from the re.split, not just extracting the ints, that's a separate issue. I want, if possible, a mixed type list returned, not a list of strings, not a list *just* of the ints, as I said like, `['level', 1, '-', 4, 'car', 10, '']`. I've also already clarified why it's different to the other answer, and that I'm looking for a single pass. All the answers are two pass, which isn't what I'm asking about. I don't think it's actually possible, but that shouldn't mean I accept one of the answers. – seaders Jun 24 '15 at 00:30

3 Answers3

3

You can use map

map(lambda x: int(x) if x.isdigit() else x, re.split(r'(\d+)', 'level1-4car10'))
Kamil
  • 369
  • 2
  • 9
  • I know map alright, but (I have now edited the title to specify this) this, unless I'm mistaken is two pass. There are a million and one options to that, what I'm specifically looking to do is a one-pass solution. Operate on the items as they're matched, instead of operating on the returned list. – seaders Jun 23 '15 at 13:56
2
[int(i) if i.isdigit() else i for i in re.split(r'(\d+)', 'level1-4car10')]
sachin saxena
  • 926
  • 5
  • 18
1

I do not know about any one pass way, but you can use list comprehension to acheieve this in one line , example -

newlist = [int(x) if x.isdigit() else x for x in re.split(r'(\d+)', 'level1-4car10') if x != '']
>>> newlist
['level', 1, '-', 4, 'car', 10]

If you want to keep the empty string as well -

newlist = [int(x) if x.isdigit() else x for x in re.split(r'(\d+)', 'level1-4car10')]
>>> newlist
['level', 1, '-', 4, 'car', 10, '']
Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176
  • Just an fyi, as with the other lines, while this is one-line, I've removed that from my question as that wasn't the important part, the important part was *one-pass*, which is why I haven't accepted any answer as correct. All are currently two-pass solutions. – seaders Jun 24 '15 at 11:27