1

我必须编写一个函数,它接受一个参数 text,其中包含一个 str 形式的文本块,并返回一个“对称”单词的排序列表。对称词被定义为一个词,其中对于所有值 i,字母 i 位置距单词开头的位置和字母 i 位置距单词末尾的位置与字母表的各个末端的距离相等。例如,bevy 是一个对称单词:b(从单词开头的 1 个位置)是字母表的第二个字母,y(从单词末尾的 1 个位置)是字母表的倒数第二个字母;e(距单词开头的 2 个位置)是字母表的第五个字母,而 v(距单词末尾的 2 个位置)是字母表的倒数第五个字母。

例如:

>>> symmetrics("boy bread aloz bray")
['aloz','boy']
>>> symmetrics("There is a car and a book;")
['a']

我能想到的解决方案就是这个,但我不能运行它,因为它是错误的:

def symmetrics(text):
    func_char= ",.?!:'\/"
    for letter in text:
        if letter in func_char:
          text = text.replace(letter, ' ') 
    alpha1 = 'abcdefghijklmnopqrstuvwxyz'
    alpha2 = 'zyxwvutsrqponmlkjihgfedcba'
    sym = []
    for word in text.lower().split():
        n = range(0,len(word))
        if word[n] == word[len(word)-1-n]:
            sym.append(word)
        return sym

上面的代码没有考虑到 alpha1 和 alpha2 的位置,因为我不知道怎么写。有没有人可以帮助我?

4

4 回答 4

3

这里有一个提示:

In [16]: alpha1.index('b')
Out[16]: 1

In [17]: alpha2.index('y')
Out[17]: 1

解决问题的另一种方法是使用以下str.translate()方法:

import string

def is_sym(word):
    alpha1 = 'abcdefghijklmnopqrstuvwxyz'
    alpha2 = 'zyxwvutsrqponmlkjihgfedcba'
    tr = string.maketrans(alpha1, alpha2)
    n = len(word) // 2
    return word[:n] == word[::-1][:n].translate(tr)

print(is_sym('aloz'))
print(is_sym('boy'))
print(is_sym('bread'))

(翻译表的构建可以很容易地分解出来。)

于 2013-04-19T04:12:57.830 回答
1

for循环可以修改为:

for word in text.lower().split():
    for n in range(0,len(word)//2):
        if alpha1.index(word[n]) != alpha2.index(word[len(word)-1-n]):
            break
    else:
        sym.append(word)
return sym
于 2013-04-19T04:27:34.573 回答
0

根据您的对称规则,我们可以使用以下is_symmetric_word函数验证对称词:

def is_symmetric_word(word):
    alpha1 = 'abcdefghijklmnopqrstuvwxyz'
    alpha2 = 'zyxwvutsrqponmlkjihgfedcba'
    length = len(word)
    for i in range(length / 2):
        if alpha1.index(word[i]) != alpha2.index(word[length - 1 - i]):
            return False

    return True

然后从文本中获取所有唯一对称词的整个函数可以定义为:

def is_symmetrics(text):
    func_char= ",.?!:'\/;"
    for letter in text:
        if letter in func_char:
          text = text.replace(letter, ' ') 
    sym = []
    for word in text.lower().split():
        if is_symmetric_word(word) and not (word in sym):
            sym.append(word)

    return sym

以下是您提供的两个测试用例:

is_symmetrics("boy bread aloz bray")           #['boy', 'aloz']
is_symmetrics("There is a car and a book;")    #['a']
于 2013-04-19T04:40:35.260 回答
0

先上代码。代码下方讨论。

import string

# get alphabet and reversed alphabet
try:
    # Python 2.x
    alpha1 = string.lowercase
except AttributeError:
    # Python 3.x and newer
    alpha1 = string.ascii_lowercase

alpha2 = alpha1[::-1]  # use slicing to reverse alpha1

# make a dictionary where the key, value pairs are symmetric
# for example symd['a'] == 'z', symd['b'] == 'y', and so on
_symd = dict(zip(alpha1, alpha2))

def is_symmetric_word(word):
    if not word:
        return False  # zero-length word is not symmetric
    i1 = 0
    i2 = len(word) - 1
    while True:
        if i1 >= i2:
            return True  # we have checked the whole string
        # get a pair of chars
        c1 = word[i1]
        c2 = word[i2]
        if _symd[c1] != c2:
            return False # the pair wasn't symmetric
        i1 += 1
        i2 -= 1

# note, added a space to list of chars to filter to a space
_filter_to_space = ",.?!:'\/ "
def _filter_ch(ch):
    if ch in _filter_to_space:
        return ' '  # return a space 
    elif ch in alpha1:
        return ch # it's an alphabet letter so return it
    else:
        # It's something we don't want.  Return empty string.
        return ''

def clean(text):
    return ''.join(_filter_ch(ch) for ch in text.lower())

def symmetrics(text):
    # filter text: keep only chars in the alphabet or spaces
    for word in clean(text).split():
        if is_symmetric_word(word):
            # use of yield makes this a generator.
            yield word

lst = list(symmetrics("The boy...is a yob."))
print(lst)  # prints: ['boy', 'a', 'yob']
  • 无需输入两次字母;我们可以反转第一个。

  • 我们可以制作一个字典,将每个字母与其对称字母配对。这将使测试任何给定的字母对是否是对称对变得非常容易。该函数zip()将两个序列配对;它们需要具有相同的长度,但由于我们使用的是字符串和字符串的反向副本,因此它们的长度将相同。

  • 最好写一个做一件事的简单函数,所以我们写一个函数,只检查字符串是否对称。如果你给它一个长度为零的字符串,它返回False,否则它设置i1为字符串中的第一个字符和i2最后一个字符。只要字符继续对称,它就会比较字符,并i1在递减时递增i2。如果两者相遇或相互通过,我们知道我们已经看到了整个字符串并且它必须是对称的,在这种情况下我们返回True; 如果它找到任何不对称的字符对,它会返回False. 我们必须检查是否i1i2在循环的顶部遇到或通过,所以它不会尝试检查一个字符是否是它自己的对称字符。(一个角色不能同时是两个'a''z'所以一个角色永远不是它自己的对称角色!)

  • 现在我们编写一个包装器来过滤掉垃圾,将字符串拆分为单词,并测试每个单词。它不仅将选定的标点字符转换为空格,而且还去除任何意外字符(任何不是批准的标点字符、空格或字母的字符)。这样我们就知道没有什么意外会进入内部函数。包装器是“懒惰的”......它是一个一次产生一个单词的生成器,而不是构建整个列表并返回它。list()将生成器的结果强制到列表中很容易使用。如果需要,您可以轻松地修改此函数以仅构建一个列表并返回它。

如果您对此有任何疑问,请询问。

编辑:代码的原始版本没有用标点符号做正确的事情;这个版本可以。另外,正如@heltonbiker 所建议的那样,当Python 有可以使用的副本时,为什么还要输入字母呢?所以我也做了这个改变。

编辑:@heltonbiker 的更改引入了对 Python 版本的依赖!我把它留了一个合适的try:/except块来处理这个问题。看来 Python 3.x 已将小写 ASCII 字母的名称改进为string.ascii_lowercase代替 plain string.lowercase

于 2013-04-19T04:47:41.023 回答