Left truncate using python 3.5 str.format?

爷,独闯天下 提交于 2020-01-03 02:41:11

问题


Q: Is is possible to create a format string using Python 3.5's string formatting syntax to left truncate?

Basically what I want to do is take a git SHA:

"c1e33f6717b9d0125b53688d315aff9cf8dd9977"

And using only a format string, get the display only the right 8 chars:

"f8dd9977"

Things Ive tried:

Invalid Syntax

>>> "{foo[-8:]}".format(foo="c1e33f6717b9d0125b53688d315aff9cf8dd9977")
>>> "{foo[-8]}".format(foo="c1e33f6717b9d0125b53688d315aff9cf8dd9977")  
>>> "{:8.-8}".format("c1e33f6717b9d0125b53688d315aff9cf8dd9977")

Wrong Result

### Results in first 8 not last 8. 
>>> "{:8.8}".format("c1e33f6717b9d0125b53688d315aff9cf8dd9977")

Works but inflexible and cumbersome

### solution requires that bar is always length of 40.
>>> bar="c1e33f6717b9d0125b53688d315aff9cf8dd9977"
>>> "{foo[32]}{foo[33]}{foo[34]}{foo[35]}{foo[36]}{foo[37]}{foo[38]}{foo[39]}".format(foo=bar)

A similar question was asked, but never answered. However mine differs in that I am limited to using only format string, I don't have the ability to change the range of the input param. This means that the following is an unacceptable solution:

>>> bar="c1e33f6717b9d0125b53688d315aff9cf8dd9977"
>>> "{0}".format(bar[-8:])

One more aspect I should clarify... the above explains the simplest form of the problem. In actual context, the problem is expressed more correctly as:

>>> import os
>>> "foo {git_sha}".format(**os.environ)

Where I want to left_truncate "git_sha" environment variable. Admittedly this is a tad more complex than simplest form, but if I can solve the simplest - I can find a way to solve the more complex.


回答1:


Is subclassing str an option?

foo="c1e33f6717b9d0125b53688d315aff9cf8dd9977"

class CustomStr(str):
    def __format__(self, spec):
        if spec == 'trunc_left':
            return self[-8:]
        else:
            return super().__format__(spec)

s = CustomStr(foo)

print('{}'.format(s))
print('{:trunc_left}'.format(s))

From there, you can do something working like so:

import os

class CustomStr(str):
    def __format__(self, spec): 
       return self[-8:]

class OsEnvironWrapper(dict):
    def __init__(self, environ):
        self.environ = environ

    def __getitem__(self, key):
        if key == 'git_sha':
            return CustomStr(self.environ[key])
        else:
            return self.environ[key]

os_environ = OsEnvironWrapper(os.environ)
print('foo {git_sha}'.format(**os_environ))

I know, the wrapper is barely acceptable, but you can tweak it to be transparent by emulating a container type properly.

[edit] See Jim's solution for a variant that does not subclass str or dict.




回答2:


So here is my solution, with thanks to @JacquesGaudin and folks on #Python for providing much guidance...

class MyStr(object):
    """Additional format string options."""
    def __init__(self, obj):
        super(MyStr, self).__init__()
        self.obj = obj

    def __format__(self, spec):
        if spec.startswith("ltrunc."):
            offset = int(spec[7:])
            return self.obj[offset:]
        else:
            return self.obj.__format__(spec)

So this works when doing this:

>>> f = {k: MyStr(v) for k, v in os.environ.items()} 
>>> "{PATH:ltrunc.-8}".format(**f)


来源:https://stackoverflow.com/questions/37974565/left-truncate-using-python-3-5-str-format

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!