【问题标题】:Python: How to check if two inputs A and B are anagrams without all punctuation, and all uppercase letters were lower case lettersPython:如何检查两个输入A和B是否是没有标点符号的字谜,所有大写字母都是小写字母
【发布时间】:2013-12-03 20:01:26
【问题描述】:

问题的第一部分是检查输入 A 和输入 B 是否是字谜,我可以很容易地做到这一点。

s = input ("Word 1?")
b = sorted(s)
c = ''.join(b)
t = input("Word 2?")
a = sorted(t)
d = ''.join(b)
if d == c:
    print("Anagram!")
else:
    print("Not Anagram!")

问题是问题的第二部分 - 如果删除了所有标点符号,我需要检查两个单词是否是字谜,大写字母变成小写字母,但问题假设没有使用空格。因此,例如,(ACdB;,.Eo,."kl) 和 (oadcbE,LK) 是字谜。问题还要求使用循环。

s = input ("Word 1?")
s = s.lower()
for i in range (0, len(s)):
    if ord(s[i]) < 97 or ord(s[i]) >122:
        s = s.replace(s[i],  '')
b = sorted(s)
c = ''.join(b)
print(c)

目前,上面的代码表示字符串索引超出范围。

【问题讨论】:

  • 我会使用正则表达式去除这些字符,然后进行正常的字谜检查。
  • 为什么不也分享这个问题呢?这是作业吗?
  • 问题要求的循环尝试如何?
  • 不顺利,我正在尝试使用 for 循环遍历字符串的每个字母的 i,检查标点符号等。是的,斯威尼,这是作业:D
  • @alex:那么你的任务就会失败,因为它要求你使用循环。 (我也会失败,因为我会在完成问题之前用生成器表达式或正则表达式编写整个事情......)

标签: python string loops


【解决方案1】:

这是您需要在伪代码中添加的循环:

s = input ("Word 1?")
s_letters = ''
for letter in s:
    if it's punctuation: skip it
    else if it's uppercase: add the lowercase version to s_letters
    else: add it to s_letters
b = sorted(s_letters)

当然,您还需要为t 添加相同的内容。如果你了解过函数,你会想把它写成一个函数,然后调用它两次,而不是复制和粘贴它并做一些小的改动。

【讨论】:

  • 关于如何检查是否为标点符号的提示:有一个字符串方法:"mystring".isalpha()(如果字符串中的所有字符都是字母,则返回 True)
  • @SweeneyTodd:很好的提示。如果 OP 真的很聪明,那甚至可能会导致他弄清楚如何仅使用 if/else 而不是 if/elif/else 来处理大写、小写和其他所有内容。
  • 对于 OP 来说可能太高级了,但我会用这个:sorted(filter(lambda x: x in string.ascii_lowercase, word.lower()))
  • @Matthias:为什么是lambda x: x in string.ascii_lowercase 而不仅仅是str.islower?如果必须将表达式包装在lambda 中,为什么要使用filter 而不是genexpr?此外,OP特别要求不要给他一个完整的答案,足以让他开始。而且,最重要的是,问题表明它必须使用for 循环,因此不使用for 循环的答案不是有效答案。
  • @abarnert:回顾我昨天写的所有代码,我似乎处于过滤和 lambda 模式。至少我没有把它作为答案。当然,for 循环可以用于输入。 :-)
【解决方案2】:

您的循环存在三个大问题。您需要解决所有这三个问题,而不仅仅是一个。


首先,s = s.replace(s[i], '') 不会将ith 字符替换为空格,而是将ith 字符以及同一字符的所有其他副本替换为空格。如果有任何重复,那将搞砸循环的其余部分。它也很慢,因为你必须一遍又一遍地搜索整个字符串。

在特定索引处替换字符的正确方法是使用切片:s = s[:i] + s[i+1:]

或者,您可以通过将字符串转换为字符列表 (s = list(s)) 来简化此操作,也可以就地对其进行变异 (del s[i])。


接下来,我们将循环 6 次,检查 s[0]s[1]s[2]s[3]s[4]s[5]。但在此过程中,我们将删除一些字符(最好是三个)。因此,其中一些索引将超出字符串的末尾,这将引发IndexError。我不会解释如何解决这个问题,因为它直接关系到下一个问题。


在循环时修改序列总是会中断循环。* 想象一下从 s = '123abc' 开始。让我们逐步完成循环。

  • i = 0,所以你检查s[0],这是1,所以你删除它,留下s = '23abc'
  • i = 1,所以你检查s[1],它是3,所以你删除它,留下s = '2abc'
  • i = 2,所以你检查s[2],这是b,所以你离开它,离开s = '2abc'
  • 等等。

通过删除 12 移至 s[0]。但是一旦你通过了i = 0,你就再也不会回来了。所以,你永远不会去检查2。您可以通过几种不同的方式来解决这个问题——向后迭代,每次通过for 执行if 而不是if,等等——但大多数这些解决方案只会加剧之前的问题。

解决这两个问题的简单方法是在循环时不要修改字符串。你可以这样做,例如,建立一个索引列表以在你进行时删除,然后以相反的顺序应用它。

但更简单的方法是在进行过程中建立您想要保留的角色。这也自动为您解决了第一个问题。

所以:

new_s = []
for i in range (0, len(s)):
    if ord(s[i]) < 97 or ord(s[i]) >122:
        pass
    else:
        new_s.append(s[i])
b = sorted(new_s)    

通过相对较小的更改,您的代码可以正常工作。


虽然我们这样做了,但有几种方法会使事情变得过于复杂。

首先,你不需要做ord(s[i]) &lt; 97;你可以做s[i] &lt; 'a'。这使事情更具可读性。

但是,更简单的是,您可以只使用isalphaislower 方法。 (由于您已经转换为lower,并且您一次只处理一个字符,这并不重要。)除了更具可读性和更难出错之外,这还具有以下优点:使用非 ASCII 字符,例如 é

最后,你几乎不想写这样的循环:

for i in range(len(s)):

这迫使你在所有地方都写s[i],而你本来可以循环遍历s

for ch in s:

所以,把它们放在一起,这是你的代码,有两个简单的修复和清理:

s = input ("Word 1?")
s = s.lower()
new_s = []
for ch in s:
    if ch.isalpha():
        new_s.append(ch)
b = sorted(new_s)
c = ''.join(b)
print(c)

如果您了解推导式或高阶函数,您就会认识到这种模式正是列表推导式的作用。因此,您可以将构建 new_s 的全部 4 行代码转换为这些单行代码中的任何一个,它们更具可读性并且更短:

new_s = (ch for ch in s if ch.isalpha)

new_s = filter(str.isalpha, s)

而事实上,整个事情都可以变成一条线:

b = sorted(ch for ch in s.lower() if ch.isalpha)

但是你的老师让你使用for 声明,所以你最好保留为for 声明。


* 这并不完全正确。如果您仅在当前索引之后修改序列的一部分,并且确保在到达每个索引时序列距离具有正确的长度,即使它之前可能具有不同的长度你做了(使用while循环而不是for循环,每次重新评估len(seq),使这部分变得微不足道而不是困难),然后它就可以工作了。但是,永远不要这样做比学习规则并仔细分析您的代码以查看您这次是否能够逃脱它更容易。

【讨论】:

    猜你喜欢
    • 2018-02-03
    • 1970-01-01
    • 2012-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-06
    • 2019-03-18
    相关资源
    最近更新 更多