Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何从字符串的开头删除到第二个特定字符?_Python_String - Fatal编程技术网

Python 如何从字符串的开头删除到第二个特定字符?

Python 如何从字符串的开头删除到第二个特定字符?,python,string,Python,String,我有一组字符串,其形式如下: 'foo.bar.baz.spam.spam.spam...etc' 它们很可能有三个或更多的多字母子串,由分隔。可能存在少于两个的格式错误的字符串,在这种情况下,我需要原始字符串 首先想到的是str.partition方法,如果我在第一个之后查找所有内容,我会使用它: 'foo.bar.baz.boink.a.b.c'.partition('.')[2] 返回 'bar.baz.boink.a.b.c' 这可以重复: def secondpartition(

我有一组字符串,其形式如下:

'foo.bar.baz.spam.spam.spam...etc'
它们很可能有三个或更多的多字母子串,由
分隔。可能存在少于两个
的格式错误的字符串,在这种情况下,我需要原始字符串

首先想到的是str.partition方法,如果我在第一个
之后查找所有内容,我会使用它:

'foo.bar.baz.boink.a.b.c'.partition('.')[2]
返回

'bar.baz.boink.a.b.c'
这可以重复:

def secondpartition(s):
    return s.partition('.')[2].partition('.')[2] or s
但这是否有效?两次调用一个方法并两次使用下标似乎并不有效。这当然不雅观。有更好的办法吗

主要问题是:

如何从
字符的开始到第二个实例删除所有内容,使
'foo.bar.baz.spam.spam.spam'
变成
'baz.spam.spam'
?这样做的最佳/最有效的方法是什么


摘要:这是最有效的方法(概括为n个字符):

但我展示了其他方法进行比较

使用字符串方法和正则表达式可以实现这一点。我会确保你能按照顺序剪切和粘贴所有内容,从而跟随翻译

首次进口:

import re
import timeit
from itertools import islice
不同的方法:字符串方法

问题中提到的方法是划分两次,但我不这么认为,因为这似乎很不雅观,而且不必要地重复:

def secondpartition(s):
    return s.partition('.')[2].partition('.')[2] or s
第二种方法是在
上拆分,从第二个开始切片,然后加入
。这给我的印象是相当优雅,我认为这会相当有效

def splitslicejoin(s):
    return '.'.join(s.split('.')[2:]) or s
dot = re.compile('\.')
def find2nddot(s):
    for i, found_dot in enumerate(dot.finditer(s)):
        if i == 1:
            return s[found_dot.end():] or s
    return s
但是切片创建了一个不必要的额外列表。但是,来自itertools模块的islice提供了一个不可用的iterable!所以我认为这会做得更好:

def splitislicejoin(s):
    return '.'.join(islice(s.split('.'), 2, None)) or s
不同的方法:正则表达式

现在是正则表达式。正则表达式想到的第一种方法是找到一个空字符串并替换为第二个

dot2 = re.compile('.*?\..*?\.')
def redot2(s):
    return dot2.sub('', s)
但我突然想到,最好使用非捕获组,并在最后返回匹配项:

dot2match = re.compile('(?:.*?\..*?\.)(.*)')
def redot2match(s):
    match = dot2match.match(s)
    if match is not None:
        return match.group(1)
    else:
        return s
最后,我可以使用正则表达式搜索找到第二个
的结尾,然后使用该索引对字符串进行切片,这将使用更多的代码,但可能仍然是快速和高效的

def splitslicejoin(s):
    return '.'.join(s.split('.')[2:]) or s
dot = re.compile('\.')
def find2nddot(s):
    for i, found_dot in enumerate(dot.finditer(s)):
        if i == 1:
            return s[found_dot.end():] or s
    return s
更新Falsetru建议使用
str.split
的maxsplit参数,我完全忘记了它。我的想法是,这可能是最直接的方法,但作业和额外的检查可能会伤害它

def maxsplittwo(s):
    parts = s.split('.', 2)
    if len(parts) <= 2:
        return s
    return parts[-1]
这是完全合适的,因为没有足够的
s将是例外

测试

现在让我们测试一下我们的函数。首先,让我们断言它们确实有效(这不是生产代码中的最佳实践,应该使用unittests,但对于StackOverflow的快速验证非常有用):

断言不会引发断言错误,因此现在让我们对它们计时,看看它们的执行情况:

性能

setup = 'from __main__ import ' + ', '.join(functions)

perfs = {}
for func in functions:
    perfs[func] = min(timeit.repeat(func + '("foo.bar.baz.a.b.c")', setup))

for func in sorted(perfs, key=lambda x: perfs[x]):
    print('{0}: {1}'.format(func, perfs[func]))
结果

Update表现最好的是falsetru的
maxsplittwo
,它略微削弱了secondpartition函数。祝贺falsetru。这是有道理的,因为这是一种非常直接的方法。而JonClements的修改甚至更好

maxsplittwoexcept: 1.01329493523
maxsplittwo: 1.08345508575
secondpartition: 1.1336209774
splitslicejoin: 1.49500417709
redot2match: 2.22423219681
splitislicejoin: 3.4605550766
find2nddot: 3.77172589302
redot2: 4.69134306908
旧版运行和分析,无falsetru的maxsplittwo和JonClements的maxsplittwo,除了:

secondpartition: 0.636116637553
splitslicejoin: 1.05499717616
redot2match: 1.10188927335
redot2: 1.6313087087
find2nddot: 1.65386564664
splitislicejoin: 3.13693511439
事实证明,最有效的方法是两次分区,尽管我的直觉不喜欢

此外,我对使用islice的直觉是错误的,在这种情况下,它的性能要差得多,因此,如果遇到类似的代码位,来自常规切片的额外列表可能是值得权衡的


在正则表达式中,我所需字符串的匹配方法在这里表现最好,几乎与
splitslicejoin

并列:这是性能最好的方法(概括为n个字符):

但我展示了其他方法进行比较

使用字符串方法和正则表达式可以实现这一点。我会确保你能按照顺序剪切和粘贴所有内容,从而跟随翻译

首次进口:

import re
import timeit
from itertools import islice
不同的方法:字符串方法

问题中提到的方法是划分两次,但我不这么认为,因为这似乎很不雅观,而且不必要地重复:

def secondpartition(s):
    return s.partition('.')[2].partition('.')[2] or s
第二种方法是在
上拆分,从第二个开始切片,然后加入
。这给我的印象是相当优雅,我认为这会相当有效

def splitslicejoin(s):
    return '.'.join(s.split('.')[2:]) or s
dot = re.compile('\.')
def find2nddot(s):
    for i, found_dot in enumerate(dot.finditer(s)):
        if i == 1:
            return s[found_dot.end():] or s
    return s
但是切片创建了一个不必要的额外列表。但是,来自itertools模块的islice提供了一个不可用的iterable!所以我认为这会做得更好:

def splitislicejoin(s):
    return '.'.join(islice(s.split('.'), 2, None)) or s
不同的方法:正则表达式

现在是正则表达式。正则表达式想到的第一种方法是找到一个空字符串并替换为第二个

dot2 = re.compile('.*?\..*?\.')
def redot2(s):
    return dot2.sub('', s)
但我突然想到,最好使用非捕获组,并在最后返回匹配项:

dot2match = re.compile('(?:.*?\..*?\.)(.*)')
def redot2match(s):
    match = dot2match.match(s)
    if match is not None:
        return match.group(1)
    else:
        return s
最后,我可以使用正则表达式搜索找到第二个
的结尾,然后使用该索引对字符串进行切片,这将使用更多的代码,但可能仍然是快速和高效的

def splitslicejoin(s):
    return '.'.join(s.split('.')[2:]) or s
dot = re.compile('\.')
def find2nddot(s):
    for i, found_dot in enumerate(dot.finditer(s)):
        if i == 1:
            return s[found_dot.end():] or s
    return s
更新Falsetru建议使用
str.split
的maxsplit参数,我完全忘记了它。我的想法是,这可能是最直接的方法,但作业和额外的检查可能会伤害它

def maxsplittwo(s):
    parts = s.split('.', 2)
    if len(parts) <= 2:
        return s
    return parts[-1]
哪一个是t