在Python下,如果要获取列表中第一次出现的子字符串或字符的索引,可以使用以下内容:
s.find("f")
但是,我想找到字符串中第一个不匹配的字符的索引。目前,我正在使用以下内容:
iNum = 0
for i, c in enumerate(line):
if(c != mark):
iNum = i
break
有没有更有效的方法来做到这一点,比如我不知道的内置函数?
答案 0 :(得分:8)
您可以使用正则表达式,例如:
>>> import re
>>> re.search(r'[^f]', 'ffffooooooooo').start()
4
[^f]
将匹配除f
以外的任何字符,并且匹配对象的start()
方法(由re.search()
返回)将给出匹配发生的索引。
要确保您还可以处理仅包含f
的空字符串或字符串,您需要检查以确保re.search()
的结果不是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)
正则表达式无法匹配。例如:
try
如果您不想使用正则表达式,那么您将不会比当前的方法做得更好。您可以使用except StopIteration
之类的内容,但是您需要使用mark
和{{1}}块来处理它,以处理仅由{{1}}个字符组成的空行或行。 / p>
答案 1 :(得分:1)
作为python并尽可能简单。 用python 2.x的打印计数器替换打印(计数器)
s = "ffffff5tgbh44frff"
counter = 0
for c in s:
counter = counter + 1
if c != "f":
break
print (counter)
答案 2 :(得分: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
>>>
答案 3 :(得分:0)
我遇到了同样的问题,并研究了解决方案的时间安排(除了来自@wwii的map / list-comp,它们明显慢于其他任何选项)。我还添加了原始版本的Cython版本。
我在Python v2.7中制作并测试了所有这些内容。我使用的是字节串(而不是Unicode字符串)。我不确定正则表达式方法是否需要不同的东西来处理Python v3中的字节串。 'mark'被硬编码为空字节。这很容易改变。
如果整个字节字符串是空字节,则所有方法都返回-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中的循环非常快。
答案 4 :(得分:0)
这是一个oneliner:
> 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'