from regparser.tree.depth import markers as mtypes, optional_rules
from regparser.tree.struct import Node
from regparser.tree.xml_parser import (
    paragraph_processor, simple_hierarchy_processor)


class IgnoreNotesHeader(paragraph_processor.BaseMatcher):
    """We don't want to include "Note:" and "Notes:" headers"""
    def matches(self, xml):
        return xml.tag == 'HD' and xml.text.lower().startswith('note')

    def derive_nodes(self, xml, processor=None):
        return []


class NoteProcessor(paragraph_processor.ParagraphProcessor):
    MATCHERS = [simple_hierarchy_processor.DepthParagraphMatcher(),
                IgnoreNotesHeader(),
                paragraph_processor.IgnoreTagMatcher('PRTPAGE')]

    def additional_constraints(self):
        return [optional_rules.limit_paragraph_types(
            mtypes.lower, mtypes.ints, mtypes.roman, mtypes.markerless)]


class NoteMatcher(paragraph_processor.BaseMatcher):
    """Processes the contents of NOTE and NOTES tags using a NoteProcessor"""
    def matches(self, xml):
        return xml.tag in ('NOTE', 'NOTES')

    def derive_nodes(self, xml, processor=None):
        processor = NoteProcessor()
        node = Node(label=[mtypes.MARKERLESS], source_xml=xml,
                    node_type=Node.NOTE)
        return [processor.process(xml, node)]

import re

from regparser.tree.depth import markers as mtypes, optional_rules
from regparser.tree.struct import Node
from regparser.tree.xml_parser import (
    paragraph_processor, simple_hierarchy_processor)


class IgnoreNotesHeader(paragraph_processor.BaseMatcher):
    """We don't want to include "Note:" and "Notes:" headers"""
    REGEX = re.compile('notes?:?\s*$', re.IGNORECASE)

    def matches(self, xml):
        return xml.tag == 'HD' and self.REGEX.match(xml.text or '')

    def derive_nodes(self, xml, processor=None):
        return []


class NoteProcessor(paragraph_processor.ParagraphProcessor):
    MATCHERS = [simple_hierarchy_processor.DepthParagraphMatcher(),
                IgnoreNotesHeader(),
                paragraph_processor.IgnoreTagMatcher('PRTPAGE')]

    def additional_constraints(self):
        return [optional_rules.limit_paragraph_types(
            mtypes.lower, mtypes.ints, mtypes.roman, mtypes.markerless)]


class NoteMatcher(paragraph_processor.BaseMatcher):
    """Processes the contents of NOTE and NOTES tags using a NoteProcessor"""
    def matches(self, xml):
        return xml.tag in ('NOTE', 'NOTES')

    def derive_nodes(self, xml, processor=None):
        processor = NoteProcessor()
        node = Node(label=[mtypes.MARKERLESS], source_xml=xml,
                    node_type=Node.NOTE)
        return [processor.process(xml, node)]

Use regex rather than string match for Note:
Use regex rather than string match for Note:

Per suggestion from @tadhg-ohiggins

+ import re
+ 
  from regparser.tree.depth import markers as mtypes, optional_rules
  from regparser.tree.struct import Node
  from regparser.tree.xml_parser import (
      paragraph_processor, simple_hierarchy_processor)
  
  
  class IgnoreNotesHeader(paragraph_processor.BaseMatcher):
      """We don't want to include "Note:" and "Notes:" headers"""
+     REGEX = re.compile('notes?:?\s*$', re.IGNORECASE)
+ 
      def matches(self, xml):
-         return xml.tag == 'HD' and xml.text.lower().startswith('note')
+         return xml.tag == 'HD' and self.REGEX.match(xml.text or '')
  
      def derive_nodes(self, xml, processor=None):
          return []
  
  
  class NoteProcessor(paragraph_processor.ParagraphProcessor):
      MATCHERS = [simple_hierarchy_processor.DepthParagraphMatcher(),
                  IgnoreNotesHeader(),
                  paragraph_processor.IgnoreTagMatcher('PRTPAGE')]
  
      def additional_constraints(self):
          return [optional_rules.limit_paragraph_types(
              mtypes.lower, mtypes.ints, mtypes.roman, mtypes.markerless)]
  
  
  class NoteMatcher(paragraph_processor.BaseMatcher):
      """Processes the contents of NOTE and NOTES tags using a NoteProcessor"""
      def matches(self, xml):
          return xml.tag in ('NOTE', 'NOTES')
  
      def derive_nodes(self, xml, processor=None):
          processor = NoteProcessor()
          node = Node(label=[mtypes.MARKERLESS], source_xml=xml,
                      node_type=Node.NOTE)
          return [processor.process(xml, node)]
  
Use regex rather than string match for Note:
## Code Before:
from regparser.tree.depth import markers as mtypes, optional_rules
from regparser.tree.struct import Node
from regparser.tree.xml_parser import (
    paragraph_processor, simple_hierarchy_processor)


class IgnoreNotesHeader(paragraph_processor.BaseMatcher):
    """We don't want to include "Note:" and "Notes:" headers"""
    def matches(self, xml):
        return xml.tag == 'HD' and xml.text.lower().startswith('note')

    def derive_nodes(self, xml, processor=None):
        return []


class NoteProcessor(paragraph_processor.ParagraphProcessor):
    MATCHERS = [simple_hierarchy_processor.DepthParagraphMatcher(),
                IgnoreNotesHeader(),
                paragraph_processor.IgnoreTagMatcher('PRTPAGE')]

    def additional_constraints(self):
        return [optional_rules.limit_paragraph_types(
            mtypes.lower, mtypes.ints, mtypes.roman, mtypes.markerless)]


class NoteMatcher(paragraph_processor.BaseMatcher):
    """Processes the contents of NOTE and NOTES tags using a NoteProcessor"""
    def matches(self, xml):
        return xml.tag in ('NOTE', 'NOTES')

    def derive_nodes(self, xml, processor=None):
        processor = NoteProcessor()
        node = Node(label=[mtypes.MARKERLESS], source_xml=xml,
                    node_type=Node.NOTE)
        return [processor.process(xml, node)]

## Instruction:
Use regex rather than string match for Note:
## Code After:
import re

from regparser.tree.depth import markers as mtypes, optional_rules
from regparser.tree.struct import Node
from regparser.tree.xml_parser import (
    paragraph_processor, simple_hierarchy_processor)


class IgnoreNotesHeader(paragraph_processor.BaseMatcher):
    """We don't want to include "Note:" and "Notes:" headers"""
    REGEX = re.compile('notes?:?\s*$', re.IGNORECASE)

    def matches(self, xml):
        return xml.tag == 'HD' and self.REGEX.match(xml.text or '')

    def derive_nodes(self, xml, processor=None):
        return []


class NoteProcessor(paragraph_processor.ParagraphProcessor):
    MATCHERS = [simple_hierarchy_processor.DepthParagraphMatcher(),
                IgnoreNotesHeader(),
                paragraph_processor.IgnoreTagMatcher('PRTPAGE')]

    def additional_constraints(self):
        return [optional_rules.limit_paragraph_types(
            mtypes.lower, mtypes.ints, mtypes.roman, mtypes.markerless)]


class NoteMatcher(paragraph_processor.BaseMatcher):
    """Processes the contents of NOTE and NOTES tags using a NoteProcessor"""
    def matches(self, xml):
        return xml.tag in ('NOTE', 'NOTES')

    def derive_nodes(self, xml, processor=None):
        processor = NoteProcessor()
        node = Node(label=[mtypes.MARKERLESS], source_xml=xml,
                    node_type=Node.NOTE)
        return [processor.process(xml, node)]
