Подтвердить что ты не робот

Нарезка строк в str.format

Я хочу сделать следующее с помощью str.format:

x,y = 1234,5678
print str(x)[2:] + str(y)[:2]

Единственный способ, которым я смог это сделать:

print '{0}{1}'.format(str(x)[2:],str(y)[:2])

Теперь, этот пример и то, что у меня на самом деле - длинная и грязная строка, и поэтому я хочу разместить нарезку внутри {}. Я изучил документы, но я не могу понять правильный синтаксис. Мой вопрос: возможно ли отрезать строки внутри поля замены?

4b9b3361

Ответ 1

Нет, вы не можете применять нарезку к строкам внутри поля замены.

Вам нужно будет обратиться к "Мини-язык спецификации формата" ; он определяет, что возможно. Этот мини-язык определяет, как вы форматируете ссылочное значение (часть после : в синтаксисе поля замены).

Ответ 2

Вы могли бы сделать что-то вроде этого.

Примечание
Это грубый пример и не следует считать полным и проверенным. Но я думаю, что это показывает вам способ начать получать, где вы хотите быть.

import string

class SliceFormatter(string.Formatter):

    def get_value(self, key, args, kwds):
        if '|' in key:
            try:
                key, indexes = key.split('|')
                indexes = map(int, indexes.split(','))
                if key.isdigit():
                    return args[int(key)][slice(*indexes)]
                return kwds[key][slice(*indexes)]
            except KeyError:
                return kwds.get(key, 'Missing')
        return super(SliceFormatter, self).get_value(key, args, kwds)


phrase = "Hello {name|0,5}, nice to meet you.  I am {name|6,9}.  That is {0|0,4}."
fmt = SliceFormatter()
print fmt.format(phrase, "JeffJeffJeff", name="Larry Bob")

OUTPUT

Hello Larry, nice to meet you.  I am Bob.  That is Jeff.

ПРИМЕЧАНИЕ 2
Нет поддержки для нарезки типа [:5] или [6:], но я думаю, что это было бы достаточно легко реализовать. Также нет проверки ошибок для индексов срезов вне диапазона и т.д.

Ответ 3

Это приятное решение и решила мою проблему нарезки. Тем не менее, я также хотел сделать повышение ценности. Например, "AVeryLongStringValue", который может понадобиться для заполнения в поле с 10 символами, может быть усечен до "... ngValue". Поэтому я расширил ваш пример, чтобы поддерживать разрезание, удаление и нормальное форматирование в одном. Это то, что я придумал.

class SliceElideFormatter(string.Formatter):
    """An extended string formatter that provides key specifiers that allow
    string values to be sliced and elided if they exceed a length limit.  The
    additional formats are optional and can be combined with normal python
    formatting.  So the whole syntax looks like:
    key[|slice-options][$elide-options[:normal-options]
    Where slice options consist of '|' character to begin a slice request,
    followed by slice indexes separated by commas.  Thus {FOO|5,} requests
    everything after the 5th element.
      The elide consist of '$' character followed by an inter max field value,
    followed by '<', '^', or '>' for pre, centered, or post eliding, followed
    by the eliding string.  Thus {FOO$10<-} would display the last 9 chanacters
    of a string longer then 10 characters with '-' prefix.
      Slicing and eliding can be combined.  For example given a dict of
    {'FOO': 'centeredtextvalue', and a format string of 
    '{FOO|1,-1$11^%2E%2E%2E}' would yield 'ente...valu'.  The slice spec removes
    the first and last characrers, and the elide spec center elides the
    remaining value with '...'.  The '...' value must be encoded in URL format
    since . is an existing special format character.
    """

    def get_value(self, key, args, kwds):
        """Called by string.Formatter for each format key found in the format
        string.  The key is checked for the presence of a slice or elide intro-
        ducer character.  If one or both a found the slice and/or elide spec
        is extracted, parsed and processed on value of found with the remaining
        key string.
        Arguments:
          key, A format key string possibly containing slice or elide specs
          args, Format values list tuple
          kwds, Format values key word dictrionary
        """
        sspec = espec = None
        if '|' in key:
            key, sspec = key.split('|')
            if '$' in sspec:
                sspec, espec = sspec.split('$')
        elif '$' in key:
            key, espec = key.split('$')
        value = args[int(key)] if key.isdigit() else kwds[key]
        if sspec:
            sindices = [int(sdx) if sdx else None
                        for sdx in sspec.split(',')]
            value = value[slice(*sindices)]
        if espec:
            espec = urllib.unquote(espec)
            if '<' in espec:
                value = self._prefix_elide_value(espec, value)
            elif '>' in espec:
                value = self._postfix_elide_value(espec, value)
            elif '^' in espec:
                value = self._center_elide_value(espec, value)
            else:
                raise ValueError('invalid eliding option %r' % elidespec)
        if sspec or espec:
            return value

        return super(SliceElideFormatter,self).get_value(key, args, kwds)

    def _center_elide_value(self, elidespec, value):
        """Return center elide value if it exceeds the elide length.
        Arguments:
          elidespec, The elide spec field extracted from key
          value, Value obtained from remaing key to maybe be elided
        """
        elidelen, elidetxt = elidespec.split('^')
        elen, vlen = int(elidelen), len(value)
        if vlen > elen:
            tlen = len(elidetxt)
            return value[:(elen-tlen)//2] + elidetxt + value[-(elen-tlen)//2:]
        return value

    def _postfix_elide_value(self, elidespec, value):
        """Return postfix elided value if it exceeds the elide length.
        Arguments:
          elidespec, The elide spec field extracted from key
          value, Value obtained from remaing key to maybe be elided
        """
        elidelen, elidetxt = elidespec.split('>')
        elen, vlen  = int(elidelen), len(value)
        if vlen > elen:
            tlen = len(elidetxt)
            return value[:(elen-tlen)] + elidetxt
        return value

    def _prefix_elide_value(self, elidespec, value):
        """Return prefix elided value if it exceeds the elide length.
        Arguments:
          elidespec, The elide spec field extracted from key
          value, Value obtained from remaing key to maybe be elided
        """
        elidelen, elidetxt = elidespec.split('<')
        elen, vlen  = int(elidelen), len(value)
        if vlen > elen:
            tlen = len(elidetxt)
            return elidetxt + value[-(elen-tlen):]
        return value

В качестве примера все три спецификации формата могут быть объединены, чтобы скопировать значения первого и последнего символов, центрировать элиту до значения 10 char и, наконец, правильно обосновать его в поле 12 char следующим образом:

sefmtr = SliceElideFormatter()
data = { 'CNT':'centeredtextvalue' }
fmt = '{CNT|1,-1$10^**:>12}'
print '%r' % sefmtr.format(fmt, *(), **data)

Выходы: 'ente ** valu'. Для всех, кого это может заинтересовать. Большое спасибо.