Я сделал поисковик по слову, который ищет, содержит ли слово поиск заданное слово. Я знаю, что мой код очень запутан, слишком много блоков try, вложенных циклов и т. Д. Возможно, я просто использовал плохой подход. Я хотел бы получить несколько советов по таким вещам. Программа предполагает, что поиск скопированного слова представляет собой идеальный прямоугольник или квадрат.
charsInRow = input("Amount of characters in each row:n")
charsInCol = input("Amount of characters in each column:n")
allChar = input("Paste all the characters in:n")
def Main():
PopulateArray()
FindWords()
def PopulateArray():
global allChar
allChar.lower()
allChar = list("".join(allChar.split()))
return allChar
def IsValid():
global charsInRow
global charsInCol
try:
charsInRow = int(charsInRow)
charsInCol = int(charsInCol)
except ValueError:
return False
return True
def FindWords():
wordToFind = input("What word would you like to search?")
wordToFind.lower()
wordSearched = ""
x = 0
for n in range(0, len(allChar) - 1):
if allChar[n] == wordToFind[0]:
while x <= len(wordToFind):
for i in range(0, len(wordToFind) * charsInRow, charsInRow):
try:
if allChar[n + i] == wordToFind[x]:
wordSearched = wordSearched + allChar[n + i]
n = n + i
break
except IndexError:
pass
try:
if allChar[n - i] == wordToFind[x]:
wordSearched = wordSearched + allChar[n-i]
n = n-i
break
except IndexError:
pass
try:
if allChar[(n + i) + 1] == wordToFind[x]:
wordSearched = wordSearched + allChar[(n+i) + 1]
n = (n+i) + 1
break
except IndexError:
pass
try:
if allChar[(n - i) + 1] == wordToFind[x]:
wordSearched = wordSearched + allChar[(n - i) + 1]
n = (n - i) + 1
break
except IndexError:
pass
try:
if allChar[(n - i) - 1] == wordToFind[x]:
wordSearched = wordSearched + allChar[(n - i) - 1]
n = (n - i) - 1
break
except IndexError:
pass
try:
if allChar[(n + i) - 1] == wordToFind[x]:
wordSearched = wordSearched + allChar[(n + i) - 1]
n = (n + i) - 1
break
except IndexError:
pass
try:
if allChar[(n + 1)] == wordToFind[x]:
wordSearched = wordSearched + allChar[n + 1]
n = n + 1
break
except IndexError:
pass
try:
if allChar[(n - 1)] == wordToFind[x]:
wordSearched = wordSearched + allChar[n - 1]
n = n - 1
break
except IndexError:
pass
x += 1
if wordToFind == wordSearched:
print(True)
else:
print(False)
print(wordSearched)
if IsValid():
if len(allChar) == int(charsInRow) * int(charsInCol):
Main()
else:
print("Not correct amount of characters, please try again")
else:
print("Please input numerical values for amount of characters.")
input()
2 ответа
Именование
Чтобы ваши имена были сложными для PEP8, как имена ваших методов, так и имена переменных должны принимать lower_snake_case, т.е.
chars_in_row
all_char
populate_array
find_words
Побочные эффекты
IsValid
обеспокоен. Оно делает нет делайте то, что написано на банке, — он не только проверяет достоверность двух переменных, но и преобразует их на месте. Кроме того, он неправильно использует глобальные переменные.
Лучшее название для этого было бы try_parse
, возможно, принимая одну строку, не затрагивая глобальные объекты и возвращая Optional[int]
то есть None
если недействительно.
Повторные попытки
Для ваших блоков, которые выглядят так:
try:
if allChar[n + i] == wordToFind[x]:
wordSearched = wordSearched + allChar[n + i]
n = n + i
break
except IndexError:
pass
есть две основные проблемы. Во-первых, вы должны просмотреть список индексов, начиная с n + i
, n - i
и т.д., чтобы вам не приходилось повторять эти блоки; Например
indices = (
n + i,
n - i,
# ...
)
for index in indices:
# ...
Кроме того, тот факт, что вы заставляете молчать IndexError
предполагает, что ваше индексирование просто неверно, и вам нужно пересмотреть границы индексации.
Компьютеры должны работать на людей, а не наоборот. Вам не нужно заставлять пользователя сообщать вам и количество строк, и столбцов; одного измерения будет достаточно. Кроме того, пользовательский терминал командной строки имеет множество приятных функций, таких как возможность вспоминать ранее введенные команды, поэтому вам не нужно вводить что-то снова и снова. В вашей программе Python нет этих удобств. Это означает, что вы можете улучшить взаимодействие с пользователем, избегая input()
любой ценой и вместо этого получение пользовательского ввода стандартным, проверенным историей способом: с помощью аргументов и параметров командной строки. Python имеет встроенную библиотеку, которая достойно справляется с такими аргументами за вас.
Глобальные переменные почти никогда не нужны (кроме констант, определений функций и определений классов). Это потому, что функции могут передавать аргументы и возвращать значения между собой.
Эти два предложения дают нам следующую структуру программы. Это всего лишь набросок. Детали реализации для проверки ввода, поиска слов и удобной печати результатов оставлены на ваше усмотрение.
import argparse
import sys
def main(args):
# Get user arguments.
opts = parse_args(args)
# Validate user inputs.
...
# Compute any need information, such as the number
# of columns and other data you might want to assist with
# searching (more on that below).
cols = len(opts.characters) // opts.rows
# Perform the word search.
searches = find_words(opts.characters, opts.rows, opts.cols, opts.words)
# Report to user. Enhance as needed.
print(searches)
def parse_args(args):
ap = argparse.ArgumentParser()
ap.add_argument('characters')
ap.add_argument('words', nargs="*")
ap.add_argument('--rows', type = int)
return ap.parse_args(args)
def find_words(characters, rows, cols, words):
# Do the searching, collecting results in some type
# of data structure or object.
searches = {
w : w in characters
for w in words
}
# Return that information to main().
# Do not print() here. Keep algorithm and presentation separate.
return searches
if __name__ == '__main__':
main(sys.argv[1:])
Как вы отметили, ваш текущий подход к поиску очень сложен и требует повторения. Из-за этого он подвержен ошибкам, его трудно рассуждать, и неудобно менять в будущем. У него также есть некоторые ошибки: например, при моей попытке использования ему не удалось найти слова на обратной диагонали. Нет особого смысла просматривать код в его текущем состоянии. Вам нужен лучший план.
Есть много способов упростить ситуацию. Одно из предложений — перестать писать логику поиска слов и вместо этого рассмотреть этот вопрос. Как можно реорганизовать данные, чтобы упростить поиск слов? Вот одна идея:
# Given this:
characters="catsdogseels"
# Create this:
grid = [
# The rows.
'cats',
'dogs',
'eels',
'cde',
# The columns.
'aoe',
'tgl',
'sss',
# The diagonals.
'c',
'da',
'eot',
'egs',
'ls',
's',
],
Строки легко создавать, используя способность Python разбивать списки различными способами. Столбцы могут быть созданы путем транспонирования строк. Вы можете поискать в Интернете, как написать transpose()
функции в нескольких строках кода.
Диагонали хитрее, но вот один способ:
# Start with the rows.
'cats'
'dogs'
'eels'
# Shift and pad them.
'cats '
' dogs '
' eels'
# Then transpose() those values and strip off the spaces.
одного измерения будет достаточно. — OP заявляет, что вход может быть квадратным или прямоугольным, поэтому, если вы сделаете вывод об одном измерении, вы не сможете подтвердить, что вход имеет правильную длину для второго. Может быть, это и нормально, но стоит отметить.
— Райндериен
избегать input () любой ценой Боюсь, оправдать не может. Есть много причин, по которым можно предпочесть stdin (который в любом случае может быть тривиально перенаправлен из командной строки), в том числе желание избежать загрязнения буфера истории или необходимость заключать ввод в кавычки, избегать крайних случаев и т. Д. Поощряйте правильный инструмент для работы. В этом случае, возможно, размеры могут быть необязательно предоставлены в качестве аргументов, но было бы неприятно нуждаться в том же для массового ввода.
— Райндериен
Под «неспособным оправдать» я имею в виду «трудно оправдать» — мои грамматические железы явно еще не проснулись.
— Райндериен
@Reinderien Возможно, я неправильно понял, что делает OP, или что-то упустил, но если вы скажете мне, что есть 5 строк и дадите мне 20 символов, 4 столбца покажутся безопасным выводом. И ваш
input()
По моему опыту, примеры в основном являются крайними случаями. Подавляющему большинству программ командной строки это не нужно. Рассмотрим набор инструментов Unix: интерактивность пользователя составляет крошечную долю от всех видов использования. Я стону каждый раз, когда вижу учебные материалы по Python, побуждающие новых программистов писать так много программ CLI, которые вращаются вокруг утомительной интерактивности в стиле вопросов и ответов. Это заблуждение и учит вредным привычкам.— FMc
Не совсем уверен, что подразумевается под циклическим просмотром списка индексов, как это будет выглядеть?
— madine816
Отредактировано; показан кортеж вместо списка, но та же идея
— Райндериен