Уведомления

Группа в Telegram: @pythonsu

#1 Июль 5, 2022 08:16:25

VladimirDeg
Зарегистрирован: 2022-06-16
Сообщения: 34
Репутация: +  0  -
Профиль   Отправить e-mail  

Нахождение подстроки в строке

Palrom
Ну так ждали от вас деталей задания, что можно засчитывать, что нельзя. Но судя по всему у вас их и нет. Скрипт ваш подойдёт только для этого конкретного списка, т.е. он бесполезен будет в большинстве случаев.
Но для сдачи наверное пойдёт.
Вот такая задача для практики дословно:

создайте файл с таким содержанием:
“”“
some line blablabla you dont need to catch this line try to catch me but not me I'm here, catch me!!!
”“”
откройте данный файл при помощи контекстного менеджера в режиме чтения и соберите список всех строк, которые содержат текст “catch me” в один список после чего выведите в консоль количество найденных в файле строк

Мой вариант:
with open("C:\\Users\\Владимир\\Desktop\\exercise28.txt", "w", encoding="utf-8" ) as file:
file.write("some line blablabla you dont need to catch this line try to catch me but not me I'm here, catch me!!!")
with open("C:\\Users\\Владимир\\Desktop\\exercise28.txt", "r") as file:
str_ = file.read()
word = str_.split()
s = "".join(word)
a = s.count("catchme")
l=[]
for i in range(a):
l.append("catch me")
print(a)
print(l)

Офлайн

#2 Июль 5, 2022 11:10:55

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9715
Репутация: +  842  -
Профиль   Отправить e-mail  

Нахождение подстроки в строке

VladimirDeg
Вот такая задача для практики дословно:
Так это надо создать файл со множеством строк, а не с одной строкой только. В каждой строке файла должен быть текст, в котором может быть часть в виде “catch me”, а может и не быть ни одной такой части. И вот те строки, в которых есть хотя бы одна часть в виде “catch me”, нужно собрать в список, добавляя их в него целиком, а потом в конце вывести количество элементов этого списка.

Берёшь каждую строку файла.
Ищешь в строке файла подстроку “catch me”.
Если подстрока найдена, то проверяешь символ слева от неё и символ справа от неё.
Если она подходит, добавляешь всю строку файла без изменений в результирующий список и переходишь к следующей строке файла.
Если она не подходит, то справа от подстроки в строке файла ищешь снова подстроку “catch me”.
Если подстрока найдена, то проверяешь символ слева от неё и символ справа от неё.
Если она подходит, добавляешь всю строку файла без изменений в результирующий список и переходишь к следующей строке файла.
Если она не подходит, то справа от подстроки в строке файла ищешь снова подстроку “catch me”.
Всё это повторяешь, пока строка не закончится.
Если строка закончилась, а в ней ничего подходящего не найдено, то просто переходишь к следующей строке и повторяешь это всё для неё.
В конце, когда все строки перебраны, выводишь результирующий список и длину этого списка.



Отредактировано py.user.next (Июль 5, 2022 11:23:42)

Офлайн

#3 Июль 6, 2022 11:15:50

Palrom
Зарегистрирован: 2022-04-21
Сообщения: 82
Репутация: +  5  -
Профиль   Отправить e-mail  

Нахождение подстроки в строке

py.user.next
Берёшь каждую строку файла.
Ищешь в строке файла подстроку “catch me”.
Если подстрока найдена, то проверяешь символ слева от неё и символ справа от неё.
Если она подходит, добавляешь всю строку файла без изменений в результирующий список и переходишь к следующей строке файла.
Если она не подходит, то справа от подстроки в строке файла ищешь снова подстроку “catch me”.
Всё это повторяешь, пока строка не закончится.
Если строка закончилась, а в ней ничего подходящего не найдено, то просто переходишь к следующей строке и повторяешь это всё для неё.
В конце, когда все строки перебраны, выводишь результирующий список и длину этого списка.
Текст на строки разбил на свой вкус, т.к. хз как должно быть по заданию.
  
with open("C:\\PythonProjects\\somefile.txt", "w", encoding="utf-8") as file:
    file.write("some line blablabla\nyou dont need to catch this line\n"
               "try to catch me but not me\nI'm here, catch me!!!")
with open("C:\\PythonProjects\\somefile.txt", "r", encoding="utf-8") as file:
    str_ = file.read().splitlines()
 
def find_word(textlist, word):
    res = []
    count = 0
    for i in textlist:
        start = i.find(word)
        while start >= 0:
            if not i[start - 1].isalpha() or start == 0:
                if not i[start + len(word)].isalpha():
                    res.append(i)
                    count += 1
            start = i.find(word, start + len(word))
    return res, count
 
print(find_word(str_, 'catch me'))
Вывод:
 (['try to catch me but not me', "I'm here, catch me!!!"], 2)

Отредактировано Palrom (Июль 6, 2022 11:16:56)

Офлайн

#4 Июль 6, 2022 11:35:13

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9715
Репутация: +  842  -
Профиль   Отправить e-mail  

Нахождение подстроки в строке

Palrom
  
def find_word(textlist, word):
    res = []
    count = 0
    for i in textlist:
        start = i.find(word)
        while start >= 0:
            if not i[start - 1].isalpha() or start == 0:
                if not i[start + len(word)].isalpha():
                    res.append(i)
                    count += 1
            start = i.find(word, start + len(word))
    return res, count

  
>>> def find_word(textlist, word):
...     res = []
...     count = 0
...     for i in textlist:
...         start = i.find(word)
...         while start >= 0:
...             if not i[start - 1].isalpha() or start == 0:
...                 if not i[start + len(word)].isalpha():
...                     res.append(i)
...                     count += 1
...             start = i.find(word, start + len(word))
...     return res, count
... 
>>> find_word(['they catch me there'], 'catch me')
(['they catch me there'], 1)
>>> 
>>> find_word(['catch me there'], 'catch me')
(['catch me there'], 1)
>>> 
>>> find_word(['they catch me'], 'catch me')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in find_word
IndexError: string index out of range
>>>

Ещё вот в этом фрагменте
Palrom
  
if not i[start - 1].isalpha() or start == 0:
При start, которая равна нулю, что будет проверяться сначала?
  
# i[start - 1] => i[0 - 1] => i[-1]
Это последний символ строки всей. Его проверка никогда не нужна, а она происходит. Это логическая ошибка, и хорошо, что она не выстрелила! А то обычно такие ошибки долго живут в коде, а потом в один прекрасный момент программа срабатывает неправильно и ракета летит не туда или там кардиостимулятор отключается.



Отредактировано py.user.next (Июль 6, 2022 12:01:23)

Офлайн

#5 Июль 6, 2022 12:14:14

Palrom
Зарегистрирован: 2022-04-21
Сообщения: 82
Репутация: +  5  -
Профиль   Отправить e-mail  

Нахождение подстроки в строке

Мдэ. Попробую починить, но мне кажется это будет уже нежизнеспособный уродец, глубиной с Марианскую впадину. Нужен другой подход наверно. Спасибо за разбор.
UPD. Перелопатил всё.

  
def find_word(textlist, word):
    punct = r' !#$%&"()*+,-./:;<=>?@[\]^_`{|}~' + "'"
    res = []
    count = 0
    for i in textlist:
        start = i.find(word)
        while start >= 0:
            if start == 0:
                if len(i) == len(word):
                    res.append(i)
                    count += 1
                elif len(i[start:start + len(word) + 1]) > len(word):
                    if i[start + len(word)] in punct:
                        res.append(i)
                        count += 1
            elif i[start - 1] in punct:
                if len(i[start:start + len(word) + 1]) > len(word):
                    if i[start + len(word)] in punct:
                        res.append(i)
                        count += 1
                elif i[-1] == word[-1]:
                    res.append(i)
                    count += 1
            start = i.find(word, start + len(word))
    return res, count
  
teststring = [' !catch me! catch melon catch mecatch me catchme! ']
print(find_word(teststring, 'catch me'))
Вывод:
 ([' !catch me! catch melon catch mecatch me catchme! '], 1) # нашёл вот это: !catch me!
  
teststring = ['catching me @catch me catch me11 catch me% ']
print(find_word(teststring, 'catch me'))
Вывод:
 (['catching me @catch me catch me11 catch me% ', 'catching me @catch me catch me11 catch me% '], 2) # нашёл вот это: @catch me, catch me%

Отредактировано Palrom (Июль 6, 2022 17:30:41)

Офлайн

#6 Июль 6, 2022 18:16:29

Palrom
Зарегистрирован: 2022-04-21
Сообщения: 82
Репутация: +  5  -
Профиль   Отправить e-mail  

Нахождение подстроки в строке

Снабдил принтами, чтобы было понятно, как я до этого докатился и что код делает на каждой строке:

  
str_ = ['some line blablabla', 'you dont need to catch this line',
        'try to catch me but not me', "I'm here, catch me!!!"]
 
def find_word(textlist, word):
    punct = r' !#$%&"()*+,-./:;<=>?@[\]^_`{|}~' + "'"
    res = []
    count = 0
    for i in textlist:
        start = i.find(word)
        while start >= 0:
            if start == 0:
                print('слово начинается с начала строки и...')
                if len(i) == len(word):
                    print('строка и есть слово.', 'УСПЕХ')
                    res.append(i)
                    count += 1
                elif len(i[start:start + len(word) + 1]) > len(word):
                    print('строка больше искомого слова и..')
                    if i[start + len(word)] in punct:
                        print('после искомого слова идёт пунктуация.', 'УСПЕХ')
                        res.append(i)
                        count += 1
                    else:
                        print('сразу после искомого слова идёт буква.')
            elif i[start - 1] in punct:
                print('слово начинается с пунктуации и...')
                if len(i[start:start + len(word) + 1]) > len(word):
                    print('строка больше искомого слова и...')
                    if i[start + len(word)] in punct:
                        print('после искомого слова идёт пунктуация.', 'УСПЕХ')
                        res.append(i)
                        count += 1
                    else:
                        print('сразу после искомого слова идёт буква.')
                elif i[-1] == word[-1]:
                    print('строка заканчивается искомым словом.', 'УСПЕХ')
                    res.append(i)
                    count += 1
            else:
                print('перед искомым словом идёт буква.')
            start = i.find(word, start + len(word))
    return res, count

 print(find_word(str_, 'line'))

Вывод:
слово начинается с пунктуации и…
строка больше искомого слова и…
после искомого слова идёт пунктуация. УСПЕХ
слово начинается с пунктуации и…
строка заканчивается искомым словом. УСПЕХ
 (['some line blablabla', 'you dont need to catch this line'], 2)

Отредактировано Palrom (Июль 6, 2022 18:17:27)

Офлайн

#7 Июль 6, 2022 22:07:44

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9715
Репутация: +  842  -
Профиль   Отправить e-mail  

Нахождение подстроки в строке

Palrom
Снабдил принтами, чтобы было понятно, как я до этого докатился и что код делает на каждой строке:
Код получился нечитаемый, из-за этого его понадобилось ещё снабжать принтами. А код должен быть читаемым без всяких принтов. Ни принтов, ни комментариев не должно быть. Комментарии пишутся только тогда, когда хочешь объяснить причину написания такой-то строки. Если пишешь комментарий, чтобы объяснить, как работает строка, значит эта строка плохо написана и её нужно переписать так, чтобы поясняющий комментарий не требовался. Лучший комментарий - это тот, которого нет, и без которого и так всё понятно сходу.

Palrom
  
                if len(i[start:start + len(word) + 1]) > len(word):
                    if i[start + len(word)] in punct:
                        res.append(i)
                        count += 1
                elif i[-1] == word[-1]:
                    res.append(i)
                    count += 1
Что делает проверка
Palrom
  
elif i[-1] == word[-1]:
Зачем она нужна вообще?

А нечитаемость кода у тебя возникает потому, что ты много вычислений вкладываешь в одну строку каждый раз. Ты лучше раздай всем вычислениям имена, а потом работай только с этими именами.

Например
Вместо вот такой проверки
  
if len(i[start:start + len(word) + 1]) > len(word):
Напиши такую
  
word_with_right_char = i[start:start + len(word) + 1]
if len(word_with_right_char) > len(word):
И так везде делай по всему коду.
Как видишь, проверка сразу проясняется гораздо больше всего лишь из-за добавленного имени.

Ещё пример
Вот у тебя участок кода
Palrom
  
elif i[start - 1] in punct:
Было
  
elif i[start - 1] in punct:
Стало
  
char_left = i[start - 1]
 
...
 
elif char_left in punct:
И всё в таком духе.

Лучше пусть будет много строк и много слов, чем одна строка без слов с кучей вложенных вычислений. Сам же потом читать будешь через полгода или год или три года и сам же будешь потом замечать, сколько времени ушло на чтение одной сложной строчки и сколько времени ушло на чтение десятка простых строк. Простые строки читаются быстрее сложных, а простые коды, состоящие из простых строк, читаются быстрее сложных кодов, состоящих из сложных строк. Ничего умного у коротких кодах нет. Только ясный код ценится, а уж длинный он получится или короткий, это как пойдёт.



Отредактировано py.user.next (Июль 6, 2022 22:14:44)

Офлайн

#8 Июль 7, 2022 10:58:44

Palrom
Зарегистрирован: 2022-04-21
Сообщения: 82
Репутация: +  5  -
Профиль   Отправить e-mail  

Нахождение подстроки в строке

py.user.next
Что делает проверка
 elif i[-1] == word[-1]:
Зачем она нужна вообще?
Сравнивает последние символы для надёжности. Ну по сути она лишняя, да. На секунду выпало из головы, что i.find(word) уже и так всё нашёл и сравнил. Уберу пожалуй.
py.user.next
лучше раздай всем вычислениям имена, а потом работай только с этими именами
Да я бы с удовольствием, но проблема в том, что многие вычисления будут производиться где-то наверху кода, при создании объекта, и тогда, когда это может быть недопустимо. Это сработает здесь:
py.user.next
  
word_with_right_char = i[start:start + len(word) + 1]
if len(word_with_right_char) > len(word):
И здесь:
py.user.next
  
char_left = i[start - 1]
elif i[start - 1] in punct:
И этот положительный пример подталкивает вроде как создать и “char_right” для этой конструкции:
 if i[start + len(word)] in punct:
И вот тут-то и будет выпадение “IndexError: string index out of range”, т.к. вычисляться это должно только после проверки len(word_with_right_char) > len(word). И выстрелит оно далеко не сразу. Мне пока сложно такие вещи на лету просчитывать, но приём возьму на вооружение.

Вот так будет выглядеть с правками:
  
def find_word(textlist, word):
    punct = r' !#$%&"()*+,-./:;<=>?@[\]^_`{|}~' + "'"
    res = []
    count = 0
    for i in textlist:
        start = i.find(word)
        while start >= 0:
            word_with_right_char = i[start:start + len(word) + 1]
            char_left = i[start - 1]
            if start == 0:
                if len(i) == len(word):
                    res.append(i)
                    count += 1
                elif len(word_with_right_char) > len(word):
                    if i[start + len(word)] in punct:
                        res.append(i)
                        count += 1
            elif char_left in punct:
                if len(word_with_right_char) > len(word):
                    if i[start + len(word)] in punct:
                        res.append(i)
                        count += 1
                else:
                    res.append(i)
                    count += 1
            start = i.find(word, start + len(word))
 
    return res, count

зы Спасибо за уделённое время

Отредактировано Palrom (Июль 7, 2022 12:15:20)

Офлайн

#9 Июль 7, 2022 14:55:47

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9715
Репутация: +  842  -
Профиль   Отправить e-mail  

Нахождение подстроки в строке

Palrom
Вот так будет выглядеть с правками:
  
def find_word(textlist, word):
    punct = r' !#$%&"()*+,-./:;<=>?@[\]^_`{|}~' + "'"
    res = []
    count = 0
    for i in textlist:
        start = i.find(word)
        while start >= 0:
            word_with_right_char = i[start:start + len(word) + 1]
            char_left = i[start - 1]
            if start == 0:
                if len(i) == len(word):
                    res.append(i)
                    count += 1
                elif len(word_with_right_char) > len(word):
                    if i[start + len(word)] in punct:
                        res.append(i)
                        count += 1
            elif char_left in punct:
                if len(word_with_right_char) > len(word):
                    if i[start + len(word)] in punct:
                        res.append(i)
                        count += 1
                else:
                    res.append(i)
                    count += 1
            start = i.find(word, start + len(word))
     return res, count
Дальше там повторяется
  
len(word_with_right_char)
Для этого можно придумать имя. Оно вычислится один раз и потом будет много раз использовано. А сейчас оно вычисляется каждый раз и на это тратится время.

Также повторяющуюся конструкцию
  
start + len(word)
можно заменить на имя.

Palrom
но приём возьму на вооружение
Делай их много, делай их повторно. Сделал один слой - сделай второй слой. Сделал второй слой - сделай третий слой. Читаемость должна повышаться. Код должен читаться, как художественная книга, - образы должны возникать из имён. Типа образ “правый символ” или образ “длина строки” или образ “слово шаблон”. А вот это типа “два плюс три плюс пять” - это не образ, а набор логических конструкций.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version