Python中如何获取一个字符串的子串?

2649

我想从字符串的第三个字符开始获取一个新的字符串,直到末尾,例如myString[2:end]。如果省略第二部分表示“到末尾”,那么如果省略第一部分,它是否从开头开始?


3
这个链接包含了一个清晰的解释,介绍如何在Python中切割字符串。 - mario ruiz
16个回答

3721
>>> x = "Hello World!"
>>> x[2:]
'llo World!'
>>> x[:2]
'He'
>>> x[:-2]
'Hello Worl'
>>> x[-2:]
'd!'
>>> x[2:-2]
'llo Worl'

Python将这个概念称为“切片”,它不仅适用于字符串。在这里查看全面介绍。


488

仅为完整性,因为没有人提到它。 数组切片的第三个参数是步长。 所以反转一个字符串就像这样简单:

some_string[::-1]

或者选择备选字符:

"H-e-l-l-o- -W-o-r-l-d"[::2] # outputs "Hello World"
能够在字符串中前进和后退的能力与从开头或结尾进行数组切片的能力保持一致。

27
@mtahmed的回答与问题直接相关。如果您想通过选择字符串中的交替字符来获取子字符串,可以使用以下方法:my_string[::2]。请注意,翻译不包括解释或其他额外内容。 - Endophage
我认为你更可能是想提到切片的第三个参数。从字符串中获取每隔一个字符可能在某些情况下是一个重要的用例,但我从未遇到过这种情况。并不是说想炫耀自己所知道的东西有什么问题 - 如果你不能这样做,那么知道这些东西有什么意义呢。:) 但是与问题相关性的论点被夸大了。 - John Lockwood
2
当然,选择备用字符的具体示例可能与问题无关,但是理解切片有第三个参数非常相关,简单的示例可以说明它的工作原理。Python社区也有很好的历史,以友好的方式教育新成员 :-) - Endophage
很明显,如果您使用 some_string [:: -1],则会返回字符串的反向顺序。但是,我真的不明白在这种情况下您如何处理其他数字?例如:test_string [5:1:-1] - 将呈现完全不同于我预期的方式。如果第一个和第二个数字为什么要影响字符串,如果第三个数字是“-1”? - Zoliqa

166

Substr() 通常(即 PHP 和 Perl)的工作方式如下:

s = Substr(s, beginning, LENGTH)

所以参数是 beginningLENGTH

但是Python的行为不同,它期望的是起始位置和结束位置加一。对于初学者来说,这很难发现。因此,正确替换 Substr(s, beginning, LENGTH) 的方法是:

s = s[ beginning : beginning + LENGTH]

91
初学者在转向Python时应该学习Pythonic的方式,而不是坚持其他语言的习惯。 - Nicu Surdu
3
为了完整起见,Java 中的 String.substring() 方法与 Python 类似,需要提供起始位置和结束位置(不包含)作为参数。这个方法让我吃了大亏,因为我以为它跟世界上其他所有的子字符串函数一样是基于长度来指定的。 - PhilHibbs
13
更符合Python风格的方法可能是s[beginning:][:length] - victortv
2
作为一个从Python开始而不是像PHP这样的“肮脏语言”的人,我认为Python在其字符串[beginning:end]方面更加简单直观。长度通常并不相关。 - Gloweye
1
@PhilHibbs,“和其他的子字符串函数一样”这个说法有些过于绝对了,因为至少还有另外两种常见的解释子字符串参数的方式。一种是 (起始位置,长度),另一种是 (起始位置,结束位置)。Python 中的 (起始位置, 结束位置+1) 确实不太常见,但与 Python 中其他操作的方式非常相似。 - AndyB
显示剩余2条评论

81
一种常见的方法是使用字符串切片。 MyString[a:b] 可以返回从索引a到(b-1)的子字符串。

30

这里似乎缺少一个例子:完全(浅层)复制。

>>> x = "Hello World!"
>>> x
'Hello World!'
>>> x[:]
'Hello World!'
>>> x==x[:]
True
>>>

这是一种常见的习语,用于创建序列类型(而不是内部字符串)的副本,[:]。浅复制列表,请参见Python list slice syntax used for no obvious reason


19
这段话与关于子字符串的问题几乎没有任何关系,甚至不适用于字符串。只需说stringA = stringB就足够了... - Nicu Surdu
2
[:]完全拷贝会创建一个新副本,使用切片语法,可以读作“从起始位置到结束位置的子字符串”。 - gimel
2
既然字符串是不可变的,那还有什么意义呢? a=b 应该足够了。 - bfontaine
1
@gimel:实际上,在不可变类型上使用[:]根本不会复制。虽然当mysequence是像strtuplebytes(Py3)或unicode(Py2)这样的不可变类型时,mysequence[:]大多是无害的,但是a = b[:]等同于a = b,它只是浪费一点时间来分派切片字节码,对象通过返回自身来响应它,因为浅复制是毫无意义的,除了对象标识测试外,它等同于只返回对自己的另一个引用。 - ShadowRanger
4
试图总结对这个答案的其他批评:在Python中,字符串是不可变的,因此没有理由复制一个字符串 - 因此s[:]根本不会复制:s ='abc'; s0 = s [:]; assert s is s0。是的,在Python中,复制列表的惯用方法是使用切片,直到列表有了list.copy,但是对于不可变类型的完整切片没有理由进行复制,因为它不能被更改,因此可能只有一个存在于内存中,我们不应该浪费时间复制它。由于这个答案是错误的,而且甚至没有回答问题 - 是否应该将其删除? - Russia Must Remove Putin

26
「有没有办法在Python中对字符串进行子串操作,从第三个字符到字符串末尾获取一个新的字符串?就像这样myString[2:end]?」」
「是的,如果你将常量单例None赋值或者绑定到名称end上,这个方法实际上是可行的。」
>>> end = None
>>> myString = '1234567890'
>>> myString[2:end]
'34567890'

切片符号有三个重要参数:

  • 起始位置
  • 结束位置
  • 步长

在没有给出时它们的默认值为None - 但我们可以明确地传递它们:

>>> stop = step = None
>>> start = 2
>>> myString[start:stop:step]
'34567890'

如果省略第二部分,则意味着“直到结束”,如果省略第一部分,是否表示从开头开始?
是的,例如:
>>> start = None
>>> stop = 2
>>> myString[start:stop:step]
'12'

请注意,我们在切片中包含起始位置,但仅到停止位置之前,不包括停止位置。
当步长为“无”时,默认情况下切片使用“1”作为步长。如果您使用负整数进行步长,则Python足够聪明,可以从末尾到开头进行操作。
>>> myString[::-1]
'0987654321'

我在解释切片符号问题中详细解释了切片符号。


12

我想对讨论添加两点:

  1. 您可以使用 None 代替空格来指定“从开头”或“到结尾”:

'abcde'[2:None] == 'abcde'[2:] == 'cde'

这在函数中特别有帮助,因为你无法将空格作为参数提供:

def substring(s, start, end):
    """Remove `start` characters from the beginning and `end` 
    characters from the end of string `s`.

    Examples
    --------
    >>> substring('abcde', 0, 3)
    'abc'
    >>> substring('abcde', 1, None)
    'bcde'
    """
    return s[start:end]
  • Python有 切片 对象:

  • idx = slice(2, None)
    'abcde'[idx] == 'abcde'[2:] == 'cde'
    

    12

    除了 "end" 之外,你的理解是正确的。这被称为切片表示法。你的例子应该写成:

    new_sub_string = myString[2:]
    

    如果省略第二个参数,则隐式为字符串的末尾。


    10
    text = "StackOverflow"
    #using python slicing, you can get different subsets of the above string
    
    #reverse of the string
    text[::-1] # 'wolfrevOkcatS' 
    
    #fist five characters
    text[:5] # Stack'
    
    #last five characters
    text[-5:] # 'rflow'
    
    #3rd character to the fifth character
    text[2:5] # 'ack'
    
    #characters at even positions
    text[1::2] # 'tcOefo'
    

    1
    文本[2:5]的注释说“rflow”,但我认为示例输出实际上是“ack”。感谢这些有用的示例! - r3cgm
    1
    文本[2:5]的评论说“rflow”,但我认为实际上示例输出应该是“ack”。感谢这些有用的示例! - undefined

    10
    如果myString包含一个从第6个字符开始并且长度为9的账户号码,那么你可以按照这种方式提取账户号码:acct = myString[6:][:9]
    如果提问者接受了这个答案,他们可能想尝试一下实验性的方法,
    myString[2:][:999999]
    

    它有效 - 没有引发错误,也没有出现默认的"字符串填充"。


    1
    我认为如果你想在 OP 的情况下使用这种方法 myString[offset:][:length],你只需要使用 myString[offset:][:] 即可。 - victortv
    1
    @VictorVal 这个答案是给那些像我一样,将Python作为第二(第三、第四……)编程语言学习,并想要一些熟悉的“语法钩子”来接近这门语言的人。任何精通该语言的专家都很可能认为我的答案有点儿愚蠢。 - CopyPasteIt
    这样的答案应该被标记为删除吗?其他答案更好地解释了类似的解决方案,看到这个答案让我想了一会儿并查找了几分钟Python,才意识到它只是那种类型的答案。 - Sebi

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接