ค้นหาการเกิดสตริงย่อยที่ n ในสตริง


118

ดูเหมือนว่ามันน่าจะเป็นเรื่องเล็กน้อย แต่ฉันยังใหม่กับ Python และต้องการทำแบบ Pythonic มากที่สุด

ฉันต้องการค้นหาดัชนีที่สอดคล้องกับการเกิดขึ้นของสตริงย่อยภายในสตริง

จะต้องมีบางสิ่งที่เทียบเท่ากับสิ่งที่ฉันต้องการทำซึ่งก็คือ

mystring.find("substring", 2nd)

คุณจะบรรลุสิ่งนี้ใน Python ได้อย่างไร?


7
ค้นหา n'th ที่เกิดขึ้นของสตริง? ฉันคิดว่ามันหมายถึงดัชนีของสิ่งที่เกิดขึ้น?
Mark Byers

2
ใช่ดัชนีของการเกิด n'th
prestomation

9
จะเกิดอะไรขึ้นหากมีการแข่งขันที่ทับซ้อนกัน? ควร find_nth ('aaaa', 'aa', 2) ส่งคืน 1 หรือ 2?
Mark Byers

ใช่ จะต้องมีบางสิ่งบางอย่างเพื่อค้นหาการเกิดขึ้นของสตริงย่อยในสตริงและแยกสตริงที่ n'th ที่เกิดขึ้นของสตริงย่อย
Reman

คำตอบ:


69

ฉันคิดว่าวิธีการซ้ำ ๆ ของมาร์คน่าจะเป็นวิธีปกติ

นี่เป็นอีกทางเลือกหนึ่งสำหรับการแยกสตริงซึ่งมักจะมีประโยชน์สำหรับการค้นหากระบวนการที่เกี่ยวข้อง:

def findnth(haystack, needle, n):
    parts= haystack.split(needle, n+1)
    if len(parts)<=n+1:
        return -1
    return len(haystack)-len(parts[-1])-len(needle)

และนี่เป็นวิธีที่รวดเร็ว (และค่อนข้างสกปรกเพราะคุณต้องเลือกแกลบที่ไม่เข้ากับเข็ม) หนึ่งซับ:

'foo bar bar bar'.replace('bar', 'XXX', 1).find('bar')

7
คำแนะนำแรกจะไม่มีประสิทธิภาพมากสำหรับสตริงขนาดใหญ่เมื่อการจับคู่ที่คุณสนใจใกล้จะเริ่มต้น มันมักจะดูทั้งสตริง มันฉลาด แต่ฉันจะไม่แนะนำสิ่งนี้ให้กับคนที่เพิ่งเริ่มใช้ Python และแค่ต้องการเรียนรู้วิธีที่ดีในการทำ
Mark Byers

3
ขอบคุณฉันชอบซับของคุณ ฉันไม่คิดว่ามันเป็นสิ่งที่อ่านได้ทันทีที่สุดในโลก แต่มันก็ไม่ได้แย่ไปกว่านั้นคนอื่น ๆ ส่วนใหญ่ด้านล่าง
prestomation

1
+1 สำหรับซับเดียวสิ่งนี้จะช่วยฉันได้ในตอนนี้ ฉันเคยคิดที่จะทำสิ่งที่เทียบเท่า.rfind('XXX')แต่มันจะแตกสลายหาก'XXX'ปรากฏในภายหลังในอินพุตต่อไป
Nikhil Chelliah

ฟังก์ชั่นนี้สมมติว่า n = 0, 1, 2, 3, ... มันจะดีที่คุณคิดว่า n = 1, 2, 3, 4, ...
สุขสันต์

75

นี่คือเวอร์ชัน Pythonic เพิ่มเติมของโซลูชันการทำซ้ำที่ตรงไปตรงมา:

def find_nth(haystack, needle, n):
    start = haystack.find(needle)
    while start >= 0 and n > 1:
        start = haystack.find(needle, start+len(needle))
        n -= 1
    return start

ตัวอย่าง:

>>> find_nth("foofoofoofoo", "foofoo", 2)
6

หากคุณต้องการค้นหาเหตุการณ์ที่ทับซ้อนกันที่ n needleคุณสามารถเพิ่มขึ้นโดย1แทนที่จะเป็นlen(needle)ดังนี้:

def find_nth_overlapping(haystack, needle, n):
    start = haystack.find(needle)
    while start >= 0 and n > 1:
        start = haystack.find(needle, start+1)
        n -= 1
    return start

ตัวอย่าง:

>>> find_nth_overlapping("foofoofoofoo", "foofoo", 2)
3

อ่านง่ายกว่าเวอร์ชันของ Mark และไม่ต้องใช้หน่วยความจำเพิ่มเติมของเวอร์ชันการแยกหรือการนำเข้าโมดูลนิพจน์ทั่วไป นอกจากนี้ยังปฏิบัติตามกฎบางประการในZen of pythonซึ่งแตกต่างจากreแนวทางต่างๆ:

  1. ง่ายดีกว่าซับซ้อน
  2. แบนดีกว่าซ้อน
  3. จำนวนการอ่าน

สามารถทำได้ในสตริงหรือไม่? เช่น find_nth (df.mystring.str, ('x'), 2) เพื่อค้นหาตำแหน่งของอินสแตนซ์ที่ 2 ของ 'x'?
Arthur D. Howland

36

สิ่งนี้จะพบการเกิดขึ้นครั้งที่สองของสตริงย่อยในสตริง

def find_2nd(string, substring):
   return string.find(substring, string.find(substring) + 1)

แก้ไข: ฉันไม่ได้คิดมากเกี่ยวกับประสิทธิภาพ แต่การเรียกซ้ำอย่างรวดเร็วสามารถช่วยในการค้นหาเหตุการณ์ที่ n:

def find_nth(string, substring, n):
   if (n == 1):
       return string.find(substring)
   else:
       return string.find(substring, find_nth(string, substring, n - 1) + 1)

โดยทั่วไปแล้วสามารถขยายเพื่อค้นหาองค์ประกอบที่ n ได้หรือไม่?
ifly6

นี่เป็นคำตอบที่ดีที่สุดของ IMHO ฉันได้เพิ่มข้อมูลเล็กน้อยสำหรับกรณีพิเศษโดยที่ n = 0
Jan Wilmans

ฉันไม่ต้องการแก้ไขโพสต์ให้สั้นลง ฉันเห็นด้วยกับคุณว่าควรถือว่า n = 0 เป็นกรณีพิเศษ
Sriram Murali

ควรปรับให้เหมาะกับกรณีที่มีnสตริงย่อยน้อยกว่าจำนวนที่เกิดขึ้น (ในกรณีนี้ค่าส่งคืนจะวนเป็นระยะ ๆ ผ่านตำแหน่งที่เกิดขึ้นทั้งหมด)
coldfix

29

การทำความเข้าใจว่า regex ไม่ใช่ทางออกที่ดีที่สุดเสมอไปฉันอาจใช้ที่นี่:

>>> import re
>>> s = "ababdfegtduab"
>>> [m.start() for m in re.finditer(r"ab",s)]
[0, 2, 11]
>>> [m.start() for m in re.finditer(r"ab",s)][2] #index 2 is third occurrence 
11

4
ความเสี่ยงที่นี่แน่นอนคือสตริงที่จะค้นหาจะมีอักขระพิเศษที่จะทำให้ regex ทำสิ่งที่คุณไม่ต้องการ การใช้ re.escape ควรแก้ปัญหานี้
Mark Byers

1
นี่ฉลาด แต่มันเป็น Pythonic จริงหรือ? ดูเหมือนจะ overkill สำหรับการค้นหาการเกิดขึ้นที่ n ของสตริงย่อยและมันไม่ง่ายเลยที่จะอ่าน เช่นเดียวกับที่คุณพูดคุณต้องนำเข้าทั้งหมดสำหรับสิ่งนี้
Todd Gamblin

เมื่อคุณใช้วงเล็บเหลี่ยมคุณจะบอกให้ Python สร้างรายการทั้งหมด วงเล็บกลมจะวนซ้ำผ่านองค์ประกอบแรกเท่านั้นซึ่งมีประสิทธิภาพมากกว่า:(m.start() for m in re.finditer(r"ab",s))[2]
emu

1
@emu ไม่สิ่งที่คุณโพสต์จะไม่ได้ผล คุณไม่สามารถใช้ดัชนีของเครื่องกำเนิดไฟฟ้าได้
Mark Amery

@MarkAmery ขอโทษ! ฉันค่อนข้างแปลกใจว่าทำไมฉันถึงโพสต์รหัสนั้น อย่างไรก็ตามวิธีแก้ปัญหาที่คล้ายกันและน่าเกลียดสามารถทำได้โดยใช้itertools.isliceฟังก์ชัน:next(islice(re.finditer(r"ab",s), 2, 2+1)).start()
emu

17

ฉันนำเสนอผลการเปรียบเทียบเปรียบเทียบแนวทางที่โดดเด่นที่สุดที่นำเสนอ ได้แก่ @bobince's findnth()(based on str.split()) เทียบกับ @ tgamblin's หรือ @Mark Byers ' find_nth()(อ้างอิงจากstr.find()) ฉันจะเปรียบเทียบกับส่วนขยาย C ( _find_nth.so) เพื่อดูว่าเราไปได้เร็วแค่ไหน นี่คือfind_nth.py:

def findnth(haystack, needle, n):
    parts= haystack.split(needle, n+1)
    if len(parts)<=n+1:
        return -1
    return len(haystack)-len(parts[-1])-len(needle)

def find_nth(s, x, n=0, overlap=False):
    l = 1 if overlap else len(x)
    i = -l
    for c in xrange(n + 1):
        i = s.find(x, i + l)
        if i < 0:
            break
    return i

แน่นอนว่าประสิทธิภาพมีความสำคัญมากที่สุดหากสตริงมีขนาดใหญ่ดังนั้นสมมติว่าเราต้องการค้นหาบรรทัดใหม่ 1000001st ('\ n') ในไฟล์ 1.3 GB ที่เรียกว่า 'bigfile' เพื่อประหยัดหน่วยความจำเราต้องการดำเนินการกับการmmap.mmapแสดงวัตถุของไฟล์:

In [1]: import _find_nth, find_nth, mmap

In [2]: f = open('bigfile', 'r')

In [3]: mm = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)

มีอยู่แล้วปัญหาที่เกิดขึ้นครั้งแรกกับfindnth()เนื่องจากวัตถุที่ไม่สนับสนุนmmap.mmap split()ดังนั้นเราต้องคัดลอกไฟล์ทั้งหมดลงในหน่วยความจำ:

In [4]: %time s = mm[:]
CPU times: user 813 ms, sys: 3.25 s, total: 4.06 s
Wall time: 17.7 s

อุ๊ย! โชคดีที่sยังพอดีกับหน่วยความจำ 4 GB ของ Macbook Air ของฉันดังนั้นเรามาเปรียบเทียบfindnth()กัน:

In [5]: %timeit find_nth.findnth(s, '\n', 1000000)
1 loops, best of 3: 29.9 s per loop

เห็นได้ชัดว่าเป็นการแสดงที่แย่มาก มาดูกันว่าแนวทางตามstr.find():

In [6]: %timeit find_nth.find_nth(s, '\n', 1000000)
1 loops, best of 3: 774 ms per loop

ดีกว่าเยอะ! เห็นได้ชัดว่าfindnth()เป็นปัญหาก็คือว่ามันถูกบังคับให้คัดลอกสตริงในช่วงsplit()ที่มีอยู่แล้วเป็นครั้งที่สองที่เราคัดลอก 1.3 GB s = mm[:]ของข้อมูลรอบหลัง มาที่นี่ในประโยชน์ที่สองของfind_nth()เราสามารถใช้ในmmโดยตรงเช่นที่ศูนย์สำเนาของแฟ้มที่จำเป็นต้องใช้:

In [7]: %timeit find_nth.find_nth(mm, '\n', 1000000)
1 loops, best of 3: 1.21 s per loop

ดูเหมือนจะมีบทลงโทษเล็กน้อยในการปฏิบัติงานmmเทียบกับsแต่นี่แสดงให้เห็นว่าfind_nth()สามารถให้คำตอบแก่เราได้ใน 1.2 วินาทีเมื่อเทียบกับfindnthทั้งหมด 47 วินาที

ฉันไม่พบว่ามีกรณีใดที่str.find()แนวทางตามนั้นแย่กว่าแนวทางพื้นฐานอย่างมีนัยสำคัญstr.split()ดังนั้น ณ จุดนี้ฉันขอโต้แย้งว่าคำตอบของ @tgamblin หรือ @Mark Byers ควรได้รับการยอมรับแทนที่จะเป็น @bobince

ในการทดสอบของฉันเวอร์ชันfind_nth()ข้างต้นเป็นโซลูชัน Python บริสุทธิ์ที่เร็วที่สุดที่ฉันสามารถหาได้ (คล้ายกับเวอร์ชันของ @Mark Byers) เรามาดูกันดีกว่าว่าโมดูลส่วนขยาย C สามารถทำได้ดีแค่ไหน นี่คือ_find_nthmodule.c:

#include <Python.h>
#include <string.h>

off_t _find_nth(const char *buf, size_t l, char c, int n) {
    off_t i;
    for (i = 0; i < l; ++i) {
        if (buf[i] == c && n-- == 0) {
            return i;
        }
    }
    return -1;
}

off_t _find_nth2(const char *buf, size_t l, char c, int n) {
    const char *b = buf - 1;
    do {
        b = memchr(b + 1, c, l);
        if (!b) return -1;
    } while (n--);
    return b - buf;
}

/* mmap_object is private in mmapmodule.c - replicate beginning here */
typedef struct {
    PyObject_HEAD
    char *data;
    size_t size;
} mmap_object;

typedef struct {
    const char *s;
    size_t l;
    char c;
    int n;
} params;

int parse_args(PyObject *args, params *P) {
    PyObject *obj;
    const char *x;

    if (!PyArg_ParseTuple(args, "Osi", &obj, &x, &P->n)) {
        return 1;
    }
    PyTypeObject *type = Py_TYPE(obj);

    if (type == &PyString_Type) {
        P->s = PyString_AS_STRING(obj);
        P->l = PyString_GET_SIZE(obj);
    } else if (!strcmp(type->tp_name, "mmap.mmap")) {
        mmap_object *m_obj = (mmap_object*) obj;
        P->s = m_obj->data;
        P->l = m_obj->size;
    } else {
        PyErr_SetString(PyExc_TypeError, "Cannot obtain char * from argument 0");
        return 1;
    }
    P->c = x[0];
    return 0;
}

static PyObject* py_find_nth(PyObject *self, PyObject *args) {
    params P;
    if (!parse_args(args, &P)) {
        return Py_BuildValue("i", _find_nth(P.s, P.l, P.c, P.n));
    } else {
        return NULL;    
    }
}

static PyObject* py_find_nth2(PyObject *self, PyObject *args) {
    params P;
    if (!parse_args(args, &P)) {
        return Py_BuildValue("i", _find_nth2(P.s, P.l, P.c, P.n));
    } else {
        return NULL;    
    }
}

static PyMethodDef methods[] = {
    {"find_nth", py_find_nth, METH_VARARGS, ""},
    {"find_nth2", py_find_nth2, METH_VARARGS, ""},
    {0}
};

PyMODINIT_FUNC init_find_nth(void) {
    Py_InitModule("_find_nth", methods);
}

นี่คือsetup.pyไฟล์:

from distutils.core import setup, Extension
module = Extension('_find_nth', sources=['_find_nthmodule.c'])
setup(ext_modules=[module])

ติดตั้งตามปกติด้วยpython setup.py install. รหัส C มีข้อได้เปรียบที่นี่เนื่องจากมีข้อ จำกัด ในการค้นหาอักขระเดี่ยว แต่มาดูกันว่าสิ่งนี้เร็วแค่ไหน:

In [8]: %timeit _find_nth.find_nth(mm, '\n', 1000000)
1 loops, best of 3: 218 ms per loop

In [9]: %timeit _find_nth.find_nth(s, '\n', 1000000)
1 loops, best of 3: 216 ms per loop

In [10]: %timeit _find_nth.find_nth2(mm, '\n', 1000000)
1 loops, best of 3: 307 ms per loop

In [11]: %timeit _find_nth.find_nth2(s, '\n', 1000000)
1 loops, best of 3: 304 ms per loop

ค่อนข้างเร็วขึ้นอย่างเห็นได้ชัด ที่น่าสนใจคือไม่มีความแตกต่างในระดับ C ระหว่างกรณีในหน่วยความจำและกรณีที่ mmapped นอกจากนี้ยังเป็นที่น่าสนใจที่จะเห็นว่า_find_nth2()ที่ตั้งอยู่บนพื้นฐานstring.hของmemchr()ฟังก์ชั่นห้องสมุดสูญเสียออกมาต่อต้านการดำเนินการตรงไปตรงมาใน_find_nth()การเพิ่มเติม 'การเพิ่มประสิทธิภาพ' ในการmemchr()จะเห็นได้ชัดว่า backfiring ...

สรุปได้ว่าการนำไปใช้งานในfindnth()(ตามstr.split()) เป็นความคิดที่ไม่ดีจริงๆเนื่องจาก (a) ทำงานได้อย่างยอดเยี่ยมสำหรับสตริงที่มีขนาดใหญ่ขึ้นเนื่องจากการคัดลอกที่จำเป็นและ (b) ไม่ได้ผลกับmmap.mmapวัตถุเลย ควรนำไปใช้ในfind_nth()(อิงstr.find()) ในทุกสถานการณ์ (ดังนั้นจึงเป็นคำตอบที่ยอมรับสำหรับคำถามนี้)

ยังมีช่องว่างสำหรับการปรับปรุงเล็กน้อยเนื่องจากส่วนขยาย C ทำงานได้เร็วกว่าโค้ด Python แท้เกือบ 4 เท่าซึ่งบ่งชี้ว่าอาจมีกรณีสำหรับฟังก์ชันไลบรารี Python โดยเฉพาะ


8

วิธีที่ง่ายที่สุด?

text = "This is a test from a test ok" 

firstTest = text.find('test')

print text.find('test', firstTest + 1)

ฉันสามารถจินตนาการได้ว่าสิ่งนี้ค่อนข้างมีประสิทธิภาพเช่นกันเมื่อเทียบกับโซลูชันอื่น ๆ
Rotareti

7

ฉันอาจจะทำสิ่งนี้โดยใช้ฟังก์ชันค้นหาที่รับพารามิเตอร์ดัชนี:

def find_nth(s, x, n):
    i = -1
    for _ in range(n):
        i = s.find(x, i + len(x))
        if i == -1:
            break
    return i

print find_nth('bananabanana', 'an', 3)

ไม่ใช่ Pythonic โดยเฉพาะอย่างยิ่งฉันเดา แต่มันง่าย คุณสามารถทำได้โดยใช้การเรียกซ้ำแทน:

def find_nth(s, x, n, i = 0):
    i = s.find(x, i)
    if n == 1 or i == -1:
        return i 
    else:
        return find_nth(s, x, n - 1, i + len(x))

print find_nth('bananabanana', 'an', 3)

มันเป็นวิธีที่ใช้งานได้ในการแก้ปัญหา แต่ฉันไม่รู้ว่ามันทำให้ Pythonic มากขึ้นหรือไม่


1
for _ in xrange(n):สามารถใช้แทนได้while n: ... n-=1
jfs

@JF Sebastian: ใช่ฉันเดาว่าเป็น Pythonic อีกหน่อย ฉันจะอัปเดต
Mark Byers

BTW: ไม่จำเป็นต้องใช้ xrange ใน Python 3 อีกต่อไป: diveintopython3.org/…
Mark Byers

1
return find_nth(s, x, n - 1, i + 1)return find_nth(s, x, n - 1, i + len(x))ควรจะเป็น ไม่ใช่เรื่องใหญ่ แต่ช่วยประหยัดเวลาในการคำนวณ
Dan Loewenherz

@dlo: อันที่จริงอาจให้ผลลัพธ์ที่แตกต่างกันในบางกรณี: find_nth ('aaaa', 'aa', 2) ของฉันให้ 1, ของคุณให้ 2 ฉันเดาว่าของคุณคือสิ่งที่ผู้โพสต์ต้องการจริงๆ ฉันจะอัปเดตรหัสของฉัน ขอบคุณสำหรับความคิดเห็น
Mark Byers

3

สิ่งนี้จะให้อาร์เรย์ของดัชนีเริ่มต้นสำหรับการจับคู่กับyourstring:

import re
indices = [s.start() for s in re.finditer(':', yourstring)]

จากนั้นรายการที่ n ของคุณจะเป็น:

n = 2
nth_entry = indices[n-1]

แน่นอนคุณต้องระมัดระวังกับขอบเขตของดัชนี คุณจะได้รับจำนวนอินสแตนซ์yourstringเช่นนี้:

num_instances = len(indices)

2

นี่คืออีกวิธีหนึ่งโดยใช้ re.finditer
ความแตกต่างก็คือสิ่งนี้มองเข้าไปในกองหญ้าเท่าที่จำเป็นเท่านั้น

from re import finditer
from itertools import dropwhile
needle='an'
haystack='bananabanana'
n=2
next(dropwhile(lambda x: x[0]<n, enumerate(re.finditer(needle,haystack))))[1].start() 

2

นี่คือรุ่นre+ อื่นitertoolsที่ควรใช้งานได้เมื่อค้นหา a strหรือRegexpObject. ฉันจะยอมรับได้อย่างอิสระว่าสิ่งนี้น่าจะได้รับการออกแบบมามากเกินไป แต่ด้วยเหตุผลบางอย่างมันทำให้ฉันเพลิดเพลิน

import itertools
import re

def find_nth(haystack, needle, n = 1):
    """
    Find the starting index of the nth occurrence of ``needle`` in \
    ``haystack``.

    If ``needle`` is a ``str``, this will perform an exact substring
    match; if it is a ``RegexpObject``, this will perform a regex
    search.

    If ``needle`` doesn't appear in ``haystack``, return ``-1``. If
    ``needle`` doesn't appear in ``haystack`` ``n`` times,
    return ``-1``.

    Arguments
    ---------
    * ``needle`` the substring (or a ``RegexpObject``) to find
    * ``haystack`` is a ``str``
    * an ``int`` indicating which occurrence to find; defaults to ``1``

    >>> find_nth("foo", "o", 1)
    1
    >>> find_nth("foo", "o", 2)
    2
    >>> find_nth("foo", "o", 3)
    -1
    >>> find_nth("foo", "b")
    -1
    >>> import re
    >>> either_o = re.compile("[oO]")
    >>> find_nth("foo", either_o, 1)
    1
    >>> find_nth("FOO", either_o, 1)
    1
    """
    if (hasattr(needle, 'finditer')):
        matches = needle.finditer(haystack)
    else:
        matches = re.finditer(re.escape(needle), haystack)
    start_here = itertools.dropwhile(lambda x: x[0] < n, enumerate(matches, 1))
    try:
        return next(start_here)[1].start()
    except StopIteration:
        return -1

2

สร้างตามคำตอบของmodle13แต่ไม่มีการreพึ่งพาโมดูล

def iter_find(haystack, needle):
    return [i for i in range(0, len(haystack)) if haystack[i:].startswith(needle)]

ฉันอยากให้นี่เป็นวิธีสตริงในตัว

>>> iter_find("http://stackoverflow.com/questions/1883980/", '/')
[5, 6, 24, 34, 42]

1
>>> s="abcdefabcdefababcdef"
>>> j=0
>>> for n,i in enumerate(s):
...   if s[n:n+2] =="ab":
...     print n,i
...     j=j+1
...     if j==2: print "2nd occurence at index position: ",n
...
0 a
6 a
2nd occurence at index position:  6
12 a
14 a

1

ให้โซลูชันที่ "ยุ่งยาก" อีกวิธีหนึ่งซึ่งใช้splitและjoin.

ในตัวอย่างของคุณเราสามารถใช้

len("substring".join([s for s in ori.split("substring")[:2]]))

1
# return -1 if nth substr (0-indexed) d.n.e, else return index
def find_nth(s, substr, n):
    i = 0
    while n >= 0:
        n -= 1
        i = s.find(substr, i + 1)
    return i

ต้องการคำอธิบาย
Ctznkane525

find_nth('aaa', 'a', 0)ผลตอบแทนในขณะที่มันควรจะกลับ1 0คุณจำเป็นต้องมีสิ่งที่ต้องการและจากนั้นกลับมาi = s.find(substr, i) + 1 i - 1
a_guest

1

วิธีแก้ปัญหาโดยไม่ต้องใช้ลูปและการเรียกซ้ำ

ใช้รูปแบบที่ต้องการในวิธีการคอมไพล์และป้อนเหตุการณ์ที่ต้องการในตัวแปร'n'และคำสั่งสุดท้ายจะพิมพ์ดัชนีเริ่มต้นของการเกิดขึ้นที่ n ของรูปแบบในสตริงที่กำหนด ที่นี่ผลลัพธ์ของตัววนซ้ำ finditer คือถูกแปลงเป็นรายการและเข้าถึงดัชนีที่ n โดยตรง

import re
n=2
sampleString="this is history"
pattern=re.compile("is")
matches=pattern.finditer(sampleString)
print(list(matches)[n].span()[0])

1

สำหรับกรณีพิเศษที่คุณค้นหา n'th ที่เกิดขึ้นของอักขระ (เช่นสตริงย่อยของความยาว 1) ฟังก์ชันต่อไปนี้จะทำงานโดยสร้างรายการตำแหน่งทั้งหมดของการเกิดขึ้นของอักขระที่กำหนด:

def find_char_nth(string, char, n):
    """Find the n'th occurence of a character within a string."""
    return [i for i, c in enumerate(string) if c == char][n-1]

หากมีน้อยกว่าที่ปรากฏของตัวละครที่ได้รับก็จะให้nIndexError: list index out of range

ได้มาจากคำตอบของ @ Zv_oDD และทำให้ง่ายขึ้นสำหรับกรณีที่มีอักขระเดี่ยว


นี่คือความสวยงาม
Hafiz Hilman Mohammad Sofian

0

การเปลี่ยนซับหนึ่งเส้นนั้นยอดเยี่ยม แต่ใช้งานได้เพราะ XX และแถบมีความยาวเท่ากัน

def ที่ดีและทั่วไปคือ:

def findN(s,sub,N,replaceString="XXX"):
    return s.replace(sub,replaceString,N-1).find(sub) - (len(replaceString)-len(sub))*(N-1)

0

นี่คือคำตอบที่คุณต้องการจริงๆ:

def Find(String,ToFind,Occurence = 1):
index = 0 
count = 0
while index <= len(String):
    try:
        if String[index:index + len(ToFind)] == ToFind:
            count += 1
        if count == Occurence:
               return index
               break
        index += 1
    except IndexError:
        return False
        break
return False

0

นี่คือวิธีแก้ปัญหาของฉันสำหรับการค้นหาการnเกิดขึ้นของbสตริงa:

from functools import reduce


def findNth(a, b, n):
    return reduce(lambda x, y: -1 if y > x + 1 else a.find(b, x + 1), range(n), -1)

เป็น Python ที่บริสุทธิ์และวนซ้ำ สำหรับ 0 หรือnใหญ่เกินไปจะคืนค่า -1 เป็นซับเดียวและสามารถใช้งานได้โดยตรง นี่คือตัวอย่าง:

>>> reduce(lambda x, y: -1 if y > x + 1 else 'bibarbobaobaotang'.find('b', x + 1), range(4), -1)
7


-2

เกี่ยวกับ:

c = os.getcwd().split('\\')
print '\\'.join(c[0:-2])

นี่ไม่ใช่คำตอบสำหรับคำถามเริ่มต้น
Jerzyk

สิ่งนี้ไม่ได้ให้คำตอบสำหรับคำถาม เมื่อคุณมีเพียงพอชื่อเสียงคุณจะสามารถที่จะแสดงความคิดเห็นในโพสต์ใด ๆ ; แทนที่จะให้คำตอบที่ไม่จำเป็นต้องชี้แจงจากผู้ถาม
Jerzyk
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.