11

在 Python 下,当您想要获取列表中第一次出现的子字符串或字符的索引时,您可以使用以下内容:

s.find("f")

但是,我想在不匹配的字符串中找到第一个字符的索引。目前,我正在使用以下内容:

iNum = 0
for i, c in enumerate(line):
  if(c != mark):
    iNum = i
    break

有没有更有效的方法来做到这一点,比如我不知道的内置函数?

4

5 回答 5

9

您可以使用正则表达式,例如:

>>> import re
>>> re.search(r'[^f]', 'ffffooooooooo').start()
4

[^f]将匹配除 之外的任何字符f,并且start()Match 对象(由 返回re.search())的方法将给出匹配发生的索引。

为了确保您还可以处理空字符串或仅包含f您想要检查的字符串,以确保re.search()is not的结果,None如果无法匹配正则表达式,则会发生这种情况。例如:

first_index = -1
match = re.search(r'[^f]', line)
if match:
    first_index = match.start()

如果您不想使用正则表达式,那么您不会比您当前的方法做得更好。你可以使用类似的东西next(i for i, c in enumerate(line) if c != mark),但你需要用一个tryexcept StopIteration块来包装它来处理空行或只包含mark字符的行。

于 2013-10-04T21:46:47.850 回答
1

像python一样,尽可能简单。用 python 2.x 的打印计数器替换 print(counter)

s = "ffffff5tgbh44frff"
counter = 0
for c in s:
    counter = counter + 1
    if c != "f":
        break

print (counter)
于 2013-10-04T21:55:52.140 回答
1

我遇到了同样的问题,并在此处研究了解决方案的时间安排(@wwii 中的 map/list-comp 除外,它们比任何其他选项都慢得多)。我还添加了原始版本的 Cython 版本。

我在 Python v2.7 中制作并测试了所有这些。我使用的是字节字符串(而不是 Unicode 字符串)。我不确定正则表达式方法是否需要不同的东西来处理 Python v3 中的字节字符串。“标记”被硬编码为空字节。这很容易改变。

如果整个字节串是空字节,所有方法都返回 -1。所有这些都在 IPython 中进行了测试(以 % 开头的行是特殊的)。

import re

def f1(s): # original version
    for i, c in enumerate(s):
        if c != b'\0': return i
    return -1

def f2(s): # @ChristopherMahan's version
    i = 0
    for c in s:
        if c != b'\0': return i
        i += 1
    return -1

def f3(s): # @AndrewClark's alternate version
    # modified to use optional default argument instead of catching StopIteration
    return next((i for i, c in enumerate(s) if c != b'\0'), -1)

def f4(s): # @AndrewClark's version
    match = re.search(br'[^\0]', s)
    return match.start() if match else -1

_re = re.compile(br'[^\0]')
def f5(s): # @AndrewClark's version w/ precompiled regular expression
    match = _re.search(s)
    return match.start() if match else -1

%load_ext cythonmagic
%%cython
# original version optimized in Cython
import cython
@cython.boundscheck(False)
@cython.wraparound(False)
def f6(bytes s):
    cdef Py_ssize_t i
    for i in xrange(len(s)):
        if s[i] != b'\0': return i
    return -1

计时结果:

s = (b'\x00' * 32) + (b'\x01' * 32) # test string

In [11]: %timeit f1(s) # original version
100000 loops, best of 3: 2.48 µs per loop

In [12]: %timeit f2(s) # @ChristopherMahan's version
100000 loops, best of 3: 2.35 µs per loop

In [13]: %timeit f3(s) # @AndrewClark's alternate version
100000 loops, best of 3: 3.07 µs per loop

In [14]: %timeit f4(s) # @AndrewClark's version
1000000 loops, best of 3: 1.91 µs per loop

In [15]: %timeit f5(s) # @AndrewClark's version w/ precompiled regular expression
1000000 loops, best of 3: 845 ns per loop

In [16]: %timeit f6(s) # original version optimized in Cython
1000000 loops, best of 3: 305 ns per loop

总体而言,@ChristopherMahan 的版本比原始版本稍快(显然enumerate比使用您自己的计数器慢)。使用next(@AndrewClark 的替代版本)方法比原来的方法慢,即使它在单行形式中本质上是相同的。

使用正则表达式(@AndrewClark 的版本)比循环快得多,特别是如果您预编译正则表达式!

然后,如果你可以使用 Cython,它是迄今为止最快的。OP 对使用正则表达式很慢的担忧得到了验证,但 Python 中的循环甚至更慢。Cython 中的循环非常快。

于 2015-06-10T05:07:23.050 回答
0

现在我很好奇这两个票价如何。

>>> # map with a partial function
>>> import functools
>>> import operator
>>> f = functools.partial(operator.eq, 'f')
>>> map(f, 'fffffooooo').index(False)
5
>>> # list comprehension
>>> [c == 'f' for c in 'ffffoooo'].index(False)
4
>>>
于 2013-10-04T23:01:11.903 回答
0

这是一个单行:

> print([a == b for (a_i, a) in enumerate("compare_me") for
(b_i, b) in enumerate("compar me") if a_i == b_i].index(False))
> 6
> "compare_me"[6]
> 'e'
于 2018-03-09T16:22:50.313 回答