首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python -用字母包装/拆包

Python -用字母包装/拆包
EN

Stack Overflow用户
提问于 2013-09-22 11:32:21
回答 3查看 1.2K关注 0票数 0

我刚刚开始学习python,我有一个让我困惑的练习:创建一个可以打包或解压一串字母的函数。所以aaabb会被包装成a3b2,反之亦然。

对于函数的打包部分,我编写了以下内容

代码语言:javascript
复制
def packer(s):
    if s.isalpha():        # Defines if unpacked

    stack = []

        for i in s:
            if s.count(i) > 1:
                if (i + str(s.count(i))) not in stack:
                    stack.append(i + str(s.count(i)))
            else:
                stack.append(i)

        print "".join(stack)

    else:
        print "Something's not quite right.."
        return False
packer("aaaaaaaaaaaabbbccccd")

这一切似乎都很合适。但是赋值说,如果输入有(例如)字母a后的b或c,那么它以后应该被解压成原来的形式。所以"aaabbkka“应该变成a3b2k2a,而不是a4b2k2。因此,我想,我不能使用"count()“命令,因为这会将整个字符串中的所有项计数,对吗?那么我在这里有什么选择呢?

关于解压-我已经想到了我的代码需要做的基本工作-

  1. 在“if s.isalpha():”和“否则”之间,我应该添加一个elif来检查字符串中是否有数字。(我想这足以决定它是包装版还是解压版)。
  2. 创建一个for循环,其中包含一个if语句,然后检查每个元素:2.1。如果它后面有一个数字>返回(或添加到一个空堆栈)数字乘以数字 2.2。如果它后面没有数字>只返回元素。

大问题2-我如何检查它是一个数字还是一个字母元素后面的一个元素在列表中?我想这必须通过切片来完成,但是那些只需要整数。这能用index命令实现吗?

此外--如果这与此相关--到目前为止,我基本上已经讨论了列表、字符串、if和for --有人告诉我,这个练习只适用于那些(...so,如果您不介意保持这个非常基本的)

所有的帮助感谢新手爱好者!

已解决:

代码语言:javascript
复制
def packer(s):
    if s.isalpha():        # Defines if unpacked
        groups= []
        last_char = None

        for c in s:
            if c == last_char:
                groups[-1].append(c)
            else:
                groups.append([c])
            last_char = c

        return ''.join('%s%s' % (g[0], len(g)>1 and len(g) or '') for g in groups)

    else:                   # Seems to be packed

        stack = ""

        for i in range(len(s)):
            if s[i].isalpha():
                if i+1 < len(s) and s[i+1].isdigit():
                    digit = s[i+1]
                    char = s[i]
                    i += 2

                    while i < len(s) and s[i].isdigit():
                        digit +=s[i]
                        i+=1
                    stack += char * int(digit)

                else:
                    stack+= s[i]
            else:
                ""
        return "".join(stack) 
print (packer("aaaaaaaaaaaabbbccccd"))
print (packer("a4b19am4nmba22")) 

这是我的最后密码。几乎成功地用for循环和if语句实现了这一切。最后,我不得不引入while循环来解决读取多位数的问题。我想我还是把它保持得够简单了。谢谢一吨的马鹿和其他人的插嘴!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-09-22 12:32:59

一个简单的解决方案:如果一个字符是不同的,那么创建一个新的组。否则,将其附加到最后一组。最后,数数所有的小组,并加入他们。

代码语言:javascript
复制
def packer(s):
    groups = []
    last_char = None
    for c in s:
        if c == last_char:
            groups[-1].append(c)
        else:
            groups.append([c])
        last_char = c
    return ''.join('%s%s'%(g[0], len(g)) for g in groups)

另一种方法是使用re

Regex r'(.)\1+'可以匹配超过1的连续字符。使用re.sub,您可以轻松地对其进行编码:

代码语言:javascript
复制
regex = re.compile(r'(.)\1+')

def replacer(match):
    return match.group(1) + str(len(match.group(0)))

regex.sub(replacer, 'aaabbkka')
#=> 'a3b2k2a'
票数 2
EN

Stack Overflow用户

发布于 2013-09-22 11:43:43

我想你可以使用`itertools.grouby的函数

例如

代码语言:javascript
复制
import itertools
data = 'aaassaaasssddee'
groupped_data = ((c, len(list(g))) for c, g in itertools.groupby(data))
result = ''.join(c + (str(n) if n > 1 else '') for c, n in groupped_data)

当然,使用生成器而不是生成器语句可以提高代码的可读性。

票数 2
EN

Stack Overflow用户

发布于 2013-09-22 13:15:22

这是我在评论中概述的算法的一个实现:

代码语言:javascript
复制
from itertools import takewhile, count, islice, izip

def consume(items):
    from collections import deque
    deque(items, maxlen=0)

def ilen(items):
    result = count()
    consume(izip(items, result))
    return next(result)

def pack_or_unpack(data):
    start = 0
    result = []

    while start < len(data):
        if data[start].isdigit():
            # `data` is packed, bail
            return unpack(data)
        run = run_len(data, start)

        # append the character that might repeat
        result.append(data[start]) 

        if run > 1:
            # append the length of the run of characters
            result.append(str(run))

        start += run

    return ''.join(result)


def run_len(data, start):
    """Return the end index of the run of identical characters starting at 
    `start`"""
    return start + ilen(takewhile(lambda c: c == data[start], 
                                  islice(data, start, None)))

def unpack(data):
    result = []
    for i in range(len(data)):
        if data[i].isdigit():
            # skip digits, we'll look for them below
            continue

        # packed character
        c = data[i]
        # number of repetitions
        n = 1
        if (i+1) < len(data) and data[i+1].isdigit():
            # if the next character is a digit, grab all the digits in the 
            # substring starting at i+1
            n = int(''.join(takewhile(str.isdigit, data[i+1:])))

        # append the repeated character
        result.append(c*n) # multiplying a string with a number repeats it
    return ''.join(result)

print pack_or_unpack('aaabbc')
print pack_or_unpack('a3b2c')
print pack_or_unpack('a10')
print pack_or_unpack('b5c5')
print pack_or_unpack('abc')

unpack()的正则化版本将是:

代码语言:javascript
复制
import re
UNPACK_RE = re.compile(r'(?P<char> [a-zA-Z]) (?P<count> \d+)?', re.VERBOSE)
def unpack_re(data):
    matches = UNPACK_RE.finditer(data)
    pairs = ((m.group('char'), m.group('count')) for m in matches)
    return ''.join(char * (int(count) if count else 1)
                   for char, count in pairs)

此代码演示了实现该算法的最直接(或“基本”)方法。它并不特别优雅,不地道,也不一定有效率。(如果是用C编写的话,但是Python有这样的警告:索引字符串将字符复制到一个新的字符串中,如果复制是用C语言进行的,并且使用Python循环实现的话,似乎过度复制数据的算法可能比试图避免这种复制更快。)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18943397

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档