循环函数直到失败的最佳方法是什么?

时间:2018-05-23 14:34:15

标签: python python-2.7 function loops

声明:

  1. 我可能会问这个问题"错误的方式" - 我还是新人 编程,所以我可能缺乏正确的术语和 理解正确地提出问题。对不起,如果我 上午。
  2. 我知道你不能用正则表达式解析[X] HTML。我没有解析 它。我只是匹配一个字符串来获取该字符串的行数。
  3. 我已经尝试了lxmliter(),以及iterparse(),我已经尝试了this waythis way。它对我没有用。我这样做。
  4. 我知道这里的代码效率不高(每次调用函数时专门编译正则表达式) - 我已经像这样重写它以提供"所需的最少代码&# 34;提出这个问题,加上它让我更容易理解我想要实现的目标。
  5. 一路走来;这段代码可以工作并完成我想要它做的事情,这基本上是采用一大堆xml记录并将其转换为{ record_id : {element_tag : element_val, element_tag : element_val, ...} }形式的字典。

    由于record_id嵌套在记录本身中,我首先使用record_splitter来确定<RECORD></RECORD>begend的计数})。我将begend传递给找到这些位置的dic_factory,对嵌套在其中的元素执行某些操作,然后设置“乞讨”。到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)
    

    这是&#34;从函数内循环#34;如果不是,那么更好的方法是什么?

2 个答案:

答案 0 :(得分:1)

tl; dr:用self.beg替换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_factorybeg作为参数,但它也可以访问对象self,并且只能从该字段读取beg

答案 1 :(得分:1)

我建议您在同一个迭代器上使用嵌套循环而不是单独的函数。 (评论中的详细信息)..

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标记)但是它们可以以相当简单的方式添加。