2

I have a string representing a date like: yymmdd (for example, 170901 for the 1st of September of 2017), obtained from a datetime object.

I want to replace the leading zeros of each field by a blank space. str.replace() won't do it it because it replaces the trailing zeros as well.

What would be the Pythonic way of substituting a character for another in a string but only in certain positions (in this case in the even indexes of the string)?

user2891462
  • 3,033
  • 2
  • 32
  • 60
  • You said it yourself. *even* indexes.. The trailing ones are on the *odd* ones. – Ma0 Sep 01 '17 at 08:47
  • 1
    https://stackoverflow.com/questions/9525944/python-datetime-formatting-without-zero-padding – timgeb Sep 01 '17 at 08:49
  • Yes, I actually perform this action, but I'd like to see the best/most elegant way of doing it. – user2891462 Sep 01 '17 at 08:49
  • 1
    Since the `datetime` module does not provide an elegant way of doing what you want your request is very uncommon/rare (because `datetime` does almost everything with dates you could think of). So allow me to ask the question: Why do you want to do this, and do you really want to? – timgeb Sep 01 '17 at 08:51
  • @timgeb Unfortunately, I do. I'm parsing files which use this ridiculous format, and I can't control it. – user2891462 Sep 01 '17 at 08:56
  • @timgeb Very true but even in the dupe you linked, the methods used are not from the `datetime` module. They are string manipulations (`lstrip`, `replace`).. In the accepted answer it even says, *"The formatting options available with datetime.strftime() will **all** zero-pad"*. – Ma0 Sep 01 '17 at 09:03
  • @user2891462 how do you wish `'000303'` to be parsed? Would it be `' 0 3 3'`? – Markus Meskanen Sep 01 '17 at 09:14
  • @MarkusMeskanen Yes. – user2891462 Sep 01 '17 at 09:59
  • In either case, I would highly suggest you to use @MosesKoledoye's answer, as it doesn't rely on string manipulation, but works with actual dates. – Markus Meskanen Sep 01 '17 at 11:24

4 Answers4

2

Would you consider this an elegant way of doing it?

s = '170901'    
res = ''.join([' ' if i%2==0 and x=='0' else x for i, x in enumerate(s)])
print(res)  # 17 9 1

You can also create a function out of it for easier use:

def date_format(date_as_str):
    return ''.join([' ' if i%2==0 and x=='0' else x for i, x in enumerate(date_as_str)])

print(date_format('170901'))  # 17 9 1
print(date_format('170910'))  # 17 910  does not remove the trailing ones..
Ma0
  • 15,057
  • 4
  • 35
  • 65
  • 1
    Yes, this one-liner suits my needs :) I'll wait a day or so to see if I get an answer I like more and otherwise accept yours. – user2891462 Sep 01 '17 at 08:58
  • I have accepted @MosesKoledoye answer because it fits my particular case better. I have upvoted yours as well since it is a good approach to more general cases. – user2891462 Sep 01 '17 at 11:49
  • @user2891462 No worries. Mose's way is the better way anyhow. – Ma0 Sep 01 '17 at 12:07
2

Convert to a datetime object, then use formatting to apply leading spaces instead of zeros to only month and day:

from datetime import datetime

s = '170901'
s = '{dt:%y}{dt.month:2d}{dt.day:2d}'.format(dt=datetime.strptime(s, '%y%m%d'))
print(s)
#17 9 1

This also ensures that values outside the limits of days and months e.g 42, cannot be parsed.

From the datetime object, you can easily switch into whatever format you want or back-and-forth the initial and latter strings:

>>> '{dt:%y}{dt.month:02d}{dt.day:02d}'.format(dt=datetime.strptime(s, '%y%m%d'))
'170901'
>>> '{dt:%y} {dt:%b} {dt.day:2d}'.format(dt=datetime.strptime(s, '%y%m%d')) 
'17 Sep  1'
Moses Koledoye
  • 77,341
  • 8
  • 133
  • 139
  • 1
    By far the best solution. `datetime` objects are way superior to playing around with strings, this allows you to do calculations with dates etc. – Markus Meskanen Sep 01 '17 at 09:18
  • I have been using `datetime` until the very end, and `strftime` is actually how I got the string :) I think this is the right answer, would you care to explain how the formatting in the third line of the first snippet works? – user2891462 Sep 01 '17 at 11:32
  • @user2891462 New style string formatting in Python supports formatting of datetime objects: https://pyformat.info/#datetime, and there's attribute access to treat some attributes specially: https://pyformat.info/#getitem_and_getattr. Combine both and you have a *powerful* tool for formatting `datetime` objects. – Moses Koledoye Sep 01 '17 at 11:36
  • 1
    Ah, I see now! `dt.month` is an integer, which gets formatted to 2 spaces with `{dt.month:02d}`. This is very clever, thank you! – user2891462 Sep 01 '17 at 11:42
1

Here's another solution, with some iteration magic to avoid building unnecessary containers. But also note my comment.

>>> from itertools import izip, chain
>>> date = '170901'
>>> ''.join((chain.from_iterable((x if x != '0' else ' ', y) for x,y in izip(*[iter(date)]*2))))
'17 9 1'
timgeb
  • 76,762
  • 20
  • 123
  • 145
0

This might be able to be shortened however; you could try and use the datetime module.

import datetime

date_str = "170901"
date = datetime.datetime.strptime(date_str, "%y%m%d")
space_date = ''.join([x.rjust(2) for x in [date.strftime("%y").lstrip('0'), str(date.month), str(date.day)]])

print(space_date) #17 9 1
jacob
  • 4,656
  • 1
  • 23
  • 32