22

名前がリストのプレフィックスのいずれかで始まるかどうかを調べてから、次のように削除する必要があります。

if name[:2] in ["i_", "c_", "m_", "l_", "d_", "t_", "e_", "b_"]:
    name = name[2:]

上記は、長さが 2 のリスト プレフィックスに対してのみ機能します。可変長プレフィックスにも同じ機能が必要です。

それはどのように効率的に行われますか (コードが少なく、パフォーマンスが良い)?

各プレフィックスを繰り返し処理し、プレフィックスname.startswith(prefix)の長さに応じて最終的に名前をスライスすることを確認する for ループは機能しますが、コードが多く、おそらく非効率的であり、「非 Pythonic」です。

誰もが良い解決策を持っていますか?

4

11 に答える 11

46

str.startswith(prefix[, start[, end]])¶

文字列がプレフィックスで始まる場合は True を返し、そうでない場合は False を返します。prefix は、検索するプレフィックスのタプルにすることもできます。オプションの start を指定すると、その位置から始まる文字列をテストします。オプションの end を指定すると、その位置で文字列の比較を停止します。

$ ipython
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: prefixes = ("i_", "c_", "m_", "l_", "d_", "t_", "e_", "b_")

In [2]: 'test'.startswith(prefixes)
Out[2]: False

In [3]: 'i_'.startswith(prefixes)
Out[3]: True

In [4]: 'd_a'.startswith(prefixes)
Out[4]: True
于 2011-09-24T16:05:50.290 に答える
14

少し読みにくいですが、これは機能します:

name=name[len(filter(name.startswith,prefixes+[''])[0]):]
于 2011-09-24T16:01:41.460 に答える
5
for prefix in prefixes:
    if name.startswith(prefix):
        name=name[len(prefix):]
        break
于 2011-09-24T15:41:29.013 に答える
3

正規表現はおそらくあなたに最高の速度を与えるでしょう:

prefixes = ["i_", "c_", "m_", "l_", "d_", "t_", "e_", "b_", "also_longer_"]
re_prefixes = "|".join(re.escape(p) for p in prefixes)

m = re.match(re_prefixes, my_string)
if m:
    my_string = my_string[m.end()-m.start():]
于 2011-09-24T16:49:29.917 に答える
2

正規表現、テスト済み:

import re

def make_multi_prefix_matcher(prefixes):
    regex_text = "|".join(re.escape(p) for p in prefixes)
    print repr(regex_text)
    return re.compile(regex_text).match

pfxs = "x ya foobar foo a|b z.".split()
names = "xenon yadda yeti food foob foobarre foo a|b a b z.yx zebra".split()

matcher = make_multi_prefix_matcher(pfxs)
for name in names:
    m = matcher(name)
    if not m:
        print repr(name), "no match"
        continue
    n = m.end()
    print repr(name), n, repr(name[n:])

出力:

'x|ya|foobar|foo|a\\|b|z\\.'
'xenon' 1 'enon'
'yadda' 2 'dda'
'yeti' no match
'food' 3 'd'
'foob' 3 'b'
'foobarre' 6 're'
'foo' 3 ''
'a|b' 3 ''
'a' no match
'b' no match
'z.yx' 2 'yx'
'zebra' no match
于 2011-09-24T22:40:30.773 に答える
2

を使用するのはfilterどうですか?

prefs = ["i_", "c_", "m_", "l_", "d_", "t_", "e_", "b_"]
name = list(filter(lambda item: not any(item.startswith(prefix) for prefix in prefs), name))

プレフィックスに対する各リスト項目の比較は、最初の一致で効率的に停止することに注意してください。anyこの動作は、値を見つけるとすぐに戻る関数によって保証されていTrueます。たとえば、次のようになります。

def gen():
    print("yielding False")
    yield False
    print("yielding True")
    yield True
    print("yielding False again")
    yield False

>>> any(gen()) # last two lines of gen() are not performed
yielding False
yielding True
True

または、re.match代わりにstartswith次を使用します。

import re
patt = '|'.join(["i_", "c_", "m_", "l_", "d_", "t_", "e_", "b_"])
name = list(filter(lambda item: not re.match(patt, item), name))
于 2011-09-24T16:46:42.423 に答える
2

プレフィックスをアンダースコアの前の文字に定義すると、チェックできます

if name.partition("_")[0] in ["i", "c", "m", "l", "d", "t", "e", "b", "foo"] and name.partition("_")[1] == "_":
    name = name.partition("_")[2]
于 2011-09-24T15:34:01.547 に答える
1

検索と効率に関して言えば、アルゴリズムを改善するためのインデックス作成手法が常に考えられます。プレフィックスの長いリストがある場合は、最初の文字でプレフィックスをdict.

このソリューションは、プレフィックスの長いリストがあり、パフォーマンスが問題になる場合にのみ価値があります。

pref = ["i_", "c_", "m_", "l_", "d_", "t_", "e_", "b_"]

#indexing prefixes in a dict. Do this only once.
d = dict()
for x in pref:
        if not x[0] in d:
                d[x[0]] = list()
        d[x[0]].append(x)


name = "c_abcdf"

#lookup in d to only check elements with the same first character.
result = filter(lambda x: name.startswith(x),\
                        [] if name[0] not in d else d[name[0]])
print result
于 2011-09-24T15:56:26.693 に答える
0

これにより、リストがその場で編集され、プレフィックスが削除されます。特定のbreakアイテムに対してプレフィックスが見つかると、残りのプレフィックスをスキップします。

items = ['this', 'that', 'i_blah', 'joe_cool', 'what_this']
prefixes = ['i_', 'c_', 'a_', 'joe_', 'mark_']

for i,item in enumerate(items):
    for p in prefixes:
        if item.startswith(p):
            items[i] = item[len(p):]
            break

print items

出力

['this', 'that', 'blah', 'cool', 'what_this']
于 2011-09-24T17:23:15.807 に答える
0

単純な正規表現を使用できます。

import re
prefixes = ("i_", "c_", "longer_")
re.sub(r'^(%s)' % '|'.join(prefixes), '', name)

または、アンダースコアの前にあるものが有効なプレフィックスである場合:

name.split('_', 1)[-1]

これにより、最初のアンダースコアの前に任意の数の文字が削除されます。

于 2018-12-04T14:07:20.793 に答える
-1
import re

def make_multi_prefix_replacer(prefixes):
    if isinstance(prefixes,str):
        prefixes = prefixes.split()
    prefixes.sort(key = len, reverse=True)
    pat = r'\b(%s)' % "|".join(map(re.escape, prefixes))
    print 'regex patern :',repr(pat),'\n'
    def suber(x, reg = re.compile(pat)):
        return reg.sub('',x)
    return suber



pfxs = "x ya foobar yaku foo a|b z."
replacer = make_multi_prefix_replacer(pfxs)               

names = "xenon yadda yeti yakute food foob foobarre foo a|b a b z.yx zebra".split()
for name in names:
    print repr(name),'\n',repr(replacer(name)),'\n'

ss = 'the yakute xenon is a|bcdf in the barfoobaratu foobarii'
print '\n',repr(ss),'\n',repr(replacer(ss)),'\n'
于 2011-09-25T01:50:05.467 に答える