# Source code for openpyxl.worksheet.header_footer

    # Copyright (c) 2010-2024 openpyxl

    # Simplified implementation of headers and footers: let worksheets have separate items

    import re
    from warnings import warn

    from openpyxl.descriptors import (
        Alias,
        Bool,
        Strict,
        String,
        Integer,
        MatchPattern,
        Typed,
    )
    from openpyxl.descriptors.serialisable import Serialisable

    from openpyxl.xml.functions import Element
    from openpyxl.utils.escape import escape, unescape

    FONT_PATTERN = '&"(?P<font>.+)"'
    COLOR_PATTERN  = "&K(?P<color>[A-F0-9]{6})"
    SIZE_REGEX = r"&(?P<size>\d+\s?)"
    FORMAT_REGEX = re.compile("{0}|{1}|{2}".format(FONT_PATTERN, COLOR_PATTERN,
                                                   SIZE_REGEX)
                              )

    def _split_string(text):
        """
        Split the combined (decoded) string into left, center and right parts

        # See http://stackoverflow.com/questions/27711175/regex-with-multiple-optional-groups for discussion
        """

        ITEM_REGEX = re.compile("""
        (&L(?P<left>.+?))?
        (&C(?P<center>.+?))?
        (&R(?P<right>.+?))?
        $""", re.VERBOSE | re.DOTALL)

        m = ITEM_REGEX.match(text)
        try:
            parts = m.groupdict()
        except AttributeError:
            warn("""Cannot parse header or footer so it will be ignored""")
            parts = {'left':'', 'right':'', 'center':''}
        return parts

    class _HeaderFooterPart(Strict):

        """
        Individual left/center/right header/footer part

        Do not use directly.

        Header & Footer ampersand codes:

        * &A   Inserts the worksheet name
        * &B   Toggles bold
        * &D or &[Date]   Inserts the current date
        * &E   Toggles double-underline
        * &F or &[File]   Inserts the workbook name
        * &I   Toggles italic
        * &N or &[Pages]   Inserts the total page count
        * &S   Toggles strikethrough
        * &T   Inserts the current time
        * &[Tab]   Inserts the worksheet name
        * &U   Toggles underline
        * &X   Toggles superscript
        * &Y   Toggles subscript
        * &P or &[Page]   Inserts the current page number
        * &P+n   Inserts the page number incremented by n
        * &P-n   Inserts the page number decremented by n
        * &[Path]   Inserts the workbook path
        * &&   Escapes the ampersand character
        * &"fontname"   Selects the named font
        * &nn   Selects the specified 2-digit font point size

        Colours are in RGB Hex
        """

        text = String(allow_none=True)
        font = String(allow_none=True)
        size = Integer(allow_none=True)
        RGB = ("^[A-Fa-f0-9]{6}$")
        color = MatchPattern(allow_none=True, pattern=RGB)

        def __init__(self, text=None, font=None, size=None, color=None):
            self.text = text
            self.font = font
            self.size = size
            self.color = color

        def __str__(self):
            """
            Convert to Excel HeaderFooter miniformat minus position
            """
            fmt = []
            if self.font:
                fmt.append(u'&"{0}"'.format(self.font))
            if self.size:
                fmt.append("&{0} ".format(self.size))
            if self.color:
                fmt.append("&K{0}".format(self.color))
            return u"".join(fmt + [self.text])

        def __bool__(self):
            return bool(self.text)

        @classmethod
        def from_str(cls, text):
            """
            Convert from miniformat to object
            """
            keys = ('font', 'color', 'size')
            kw = dict((k, v) for match in FORMAT_REGEX.findall(text)
                      for k, v in zip(keys, match) if v)

            kw['text'] = FORMAT_REGEX.sub('', text)

            return cls(**kw)