Лучший способ зациклить функции до отказа? - PullRequest
0 голосов
/ 23 мая 2018

Отказ от ответственности:

  1. Возможно, я задаю этот вопрос "неправильным путем" - я все еще новичок в программировании, поэтому мне может не хватать правильной терминологии и понимания, чтобы правильно задать вопрос.Извините за это, если я.
  2. Я знаю, что вы не можете разобрать [X] HTML с регулярным выражением.Я не разбираю это.Я просто сопоставляю строку, чтобы получить количество строк этой строки.
  3. Я пробовал lxml и iter(), а также iterparse(), и я попробовал это вот так и вот так .Это не сработало для меня.Я делаю это таким образом.
  4. Я знаю, что код здесь неэффективен (в частности, компиляция выражения регулярного выражения при каждом вызове функции) - я переписал это так, чтобы обеспечить "минимально необходимый код », чтобы задать вопрос, плюс мне немного легче понять, чего я пытаюсь достичь, я думаю.

С этим до конца;этот код работает и выполняет то, что я хочу, то есть, по сути, он берет огромный набор xml-записей и превращает его в словарь в виде { record_id : {element_tag : element_val, element_tag : element_val, ...} }.

, так как record_id вложен вСаму запись, я сначала использую record_splitter, чтобы определить количество <RECORD> и </RECORD> (beg и end).Я передаю beg и end в dic_factory, который находит эти позиции, что-то делает с элементами, вложенными в него, затем устанавливает 'beg' в end +1 и передает его обратно в функцию record_splitter.

Мой вопрос заключается в том, есть ли лучший способ реализовать этот цикл между функциями, предпочтительно в if __name__ == '__main__', чтобы я мог переместить больше моих констант (например, операторов регулярных выражений) в это какхорошо.

Code:
    # stored as a text file, but here for clarity

    list_of_lines = """
    <RECORD>
      <TITLE>MISS</TITLE>
      <NAME>ELIZABETH</NAME>
      <SURNAME>II</SURNAME>
      <ADDRESS1>1 BUCKINGHAM PALACE</ADDRESS1>
      <ADDRESS2>LONDON</ADDRESS2>
      <ADDRESS3>GREATER LONDON</ADDRESS3>
      <POST_CODE>W1 11A</POST_CODE>
      <CASE_NUM>Q1QQ1234</CASE_NUM>
      <ID>32145698</ID>
      <LAST_UPDATE_DATE>2016-12-12</LAST_UPDATE_DATE>
     </RECORD>
     <RECORD>
      <TITLE>MR</TITLE>
      <NAME>PRINCE</NAME>
      <SURNAME>PHILLIP</SURNAME>
      <ADDRESS1>1 BUCKINGHAM PALACE</ADDRESS1>
      <ADDRESS2>LONDON</ADDRESS2>
      <ADDRESS3>GREATER LONDON</ADDRESS3>
      <POST_CODE>W1 11A</POST_CODE>
      <CASE_NUM>K5KK4321</CASE_NUM>
      <ID>56987412</ID>
      <LAST_UPDATE_DATE>2017-01-16</LAST_UPDATE_DATE>
     </RECORD>
     <RECORD>
    """

class recordManager:

    def __init__(self):
        self.r_location = "list_of_lines.txt"

    def record_splitter(self, beg):

        re_beg_spl = re.compile(".*<RECORD>")
        re_end_spl = re.compile(".*(<\\/RECORD>)")

        end = None

        for count, line in enumerate( open(self.r_location) ):
            if count > beg:
                if re_end_spl.match(line):
                    end = count

                    if not re_end_spl.match(line):
                        if re_beg_spl.match(line):
                            beg = count
                    else:
                        break

                    recordManager.dic_factory(self, beg, end)


    def dic_factory(self, beg, end):

        re_casenum = re.compile(".*<CASE_NUM>(.*)<\\/CASE_NUM>")
        re_tag_val = re.compile(".*<(\\w*)>(.*)<.*")

        id_ = None
        tags = []
        vals = []

        for count, line in enumerate( open(self.r_location) ):

            if beg < count < end:
                if re_casenum.match(line):
                    m = re_casenum.match(line)
                    id_ = m.group(1)

                if re_tag_val.match(line):
                    m = re_tag_val.match(line)
                    tags.append( m.group(1) )
                    vals.append( m.group(2) )

        beg = end +1
        print {id_ : dict(zip(tags, vals)) }
        # {32145698 : {'POST_CODE': 'W1 11A', 'SURNAME': 'II', 'NAME': 'ELIZABETH', 'TITLE': 'MISS', 'ADDRESS1': '1 BUCKINGHAM PALACE', 'ADDRESS2': 'LONDON', 'ADDRESS3': 'GREATER LONDON', 'RECORD_TYPE': '1', 'CASE_NUM': 'Q1QQ1234', 'LAST_UPDATE_DATE': '2016-12-12', 'ID': '32145698'}}

        self.record_splitter(beg)


if __name__ == '__main__':
    inst_fol = record_manager(file)
    recordManager.record_splitter(inst_folder, 0)

Моя проблема в том, что я не знаю, как зациклить 'умолять' вернуться к record_splitter вне функций / из main :

if __name__ == '__main__':
    inst_fol = record_manager(file)
    beg, end = recordManager.record_splitter(inst_folder, 0)

Это "зацикливание внутри функций", и если нет, то какой подход лучше?

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Я собираюсь предложить вам использовать вложенные циклы на одном итераторе вместо отдельных функций.(подробности в комментариях) ..

class recordManager:

    def __init__(self):
        self.r_location = "list_of_lines.txt"
        self.records = [] #perhaps we want to store all the records we find?

    def find_records(self):

        re_beg_spl = re.compile(".*<RECORD>")
        re_end_spl = re.compile(".*(<\\/RECORD>)")
        re_casenum = re.compile(".*<CASE_NUM>(.*)<\\/CASE_NUM>") #move these up here since we're rolling the two functions into one
        re_tag_val = re.compile(".*<(\\w*)>(.*)<.*")

        with open(self.r_location) as f: #use the "with open() as f:" idiom to ensure file gets closed when you're done with it
            for line in f: #iterating over an open file defaults to line by line and we won't need line number with the nested loop approach
                if re_beg_spl.match(line): #start a new record
                    tags = {} #container for element tags and values
                    case = '' #case number for this record
                    for line in f: #re-use iterator for inner loop so lines are consumed (outer loop will pick up where inner loop leaves off)
                        match_case = re_casenum.match(line)
                        match_elem = re_tag_val.match(line)
                        match_end = re_end_spl.match(line)
                        if match_case:
                            case = match_case.group(1) #are match groups 1 or 0 indexed? I didn't look it up..
                        elif match_elem:
                            tags[match_elem.group(1)] = match_elem.group(2)
                        elif match_end: #end of a record -- save info and break out of inner loop
                            caseinfo = {case: tags}
                            print(caseinfo)
                            self.records.append(caseinfo)
                            break

Использование этого подхода ограничивает вашу потребность в эффективно глобальных переменных (используя атрибут объекта для передачи состояния), что обеспечивает большую структуру вашей программы (и делает ее проще),Это также исключает повторное зацикливание строк, которые вы уже исследовали, и повторное чтение файлов несколько раз (что может быть вашим фактором ограничения скорости, если у вас механический жесткий диск).Я не включил проверки на возможные разрывы в структуре (например, отсутствующий конечный тег или тег id), но их можно добавить довольно простым способом.

0 голосов
/ 23 мая 2018

tl; dr: замените beg на self.beg

Я бы рекомендовал сделать beg полем в вашем классе.Помните, что каждый используемый вами метод имеет доступ к self, что является преимуществом при организации этой работы в класс:

, поэтому __init__ становится:

    def __init__(self):
    self.r_location = "list_of_lines.txt"
    self.beg = 0

Теперь везде, где вы используете beg, вы называете его self.beg.

Например:

        for count, line in enumerate( open(self.r_location) ):
        if count > self.beg:
            if re_end_spl.match(line):
                end = count

                if not re_end_spl.match(line):
                    if re_beg_spl.match(line):
                        self.beg = count
                else:
                    break

                recordManager.dic_factory(self, self.beg, end)

Обратите внимание, что есть дальнейшая возможность для консолидации: dic_factoryпринимает в качестве аргумента beg, но он также имеет доступ к объекту self и может просто прочитать beg из этого поля.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...