Python regex optional capture group or lastindex
Question: I'm searching a file line by line for sections and sub sections using python.

    
    
       *** Section with no sub section
      *** Section with sub section ***
               *** Sub Section ***
      *** Another section
    

Sections start with 0-2 spaces followed by three asterisk, sub sections have
2+ white spaces then asterisks.

I write out the sections / sub sections without "***'s"; currently (using
re.sub).

    
    
    Section: Section with no sub section
    Section: Section with sub section
    Sub-Section: Sub Section
    Section: Another Section
    

**QUESTION 1** : Is there a python regexp with capture groups that would let
me access the section/sub section names as a capture group?

**QUESTION 2** : How would the regexp groups allow me to ID section or sub
section (possibly based on the number of /content in a match.group)?

**EXAMPLE (NON WORKING):**

    
    
    match=re.compile('(group0 *** )(group1 section title)(group2 ***)')
    sectionTitle = match.group(1)
    if match.lastindex = 0: sectionType = section with no subs
    if match.lastindex = 1: sectionType = section with subs
    if match.lastindex = 2: sectionTpe = sub section
    

**PREVIOUS ATTEMPTS** I have been able to capture sections or sub sections
with separate regexps and if statements, but I want to do it all at once.
Something like the line below; has trouble with the second groups greediness.

    
    
    '(^\*{3}\s)(.*)(\s\*{3}$)'
    

I can't seem to get the greedyness or optional groups to work together.
<http://pythex.org/> has been very helpful to this point.

Also, I tried capturing the asterisks '(*{3})' and then determining if section
or sub section based on the number of groups found.

    
    
    sectionRegex=re.compile('(\*{3})'
    m=re.search(sectionRegex)
      if m.lastindex == 0:
           sectionName = re.sub(sectionRegex,'',line) 
           #Set a section flag
      if m.lastindex ==1:
           sectionName = re.sub(sectionRegex,''line)
           #Set a sub section flag.
    

**THANKS** Maybe I'm going at this totally wrong. Any help is appreciated.

**Latest Update** I've been playing with Pythex, answers, and other research.
I'm now spending more time capturing the words:

    
    
    ^[a-zA-Z]+$
    

and counting the number of asterisk matches to determine "level". I am still
searching for a single regexp to match the two - three "groups". May not
exist.

Thanks.


Answer: > **QUESTION 1** : Is there a python regexp with capture groups that would let
> me access the section/sub section names as a capture group?
>

>> a single regexp to match the two - three "groups". May not exist

Yes, it can be done. We can decomposs the conditions as the following tree:

  * `Start of line` **+** `0 to 2 spaces`
  * Any of the 2 alternations: 
    1. `***` **+** `Any text`[group 1]
    2. `1+ spaces` **+** `***` **+** `Any text`[group 2]
  * `***`(optional) **+** `End of line`

  
And the above tree can be expressed with the pattern:

    
    
    ^[ ]{0,2}(?:[*]{3}(.*?)|[ ]+[*]{3}(.*?))(?:[*]{3})?$
    

  * [regex101 DEMO](https://regex101.com/r/mV0gN4/1)

Notice the _Section_ and _Sub-Section_ are being captured by different groups
([group 1] and [group 2] respectively). They both use the same syntax `.*?`,
both with a [lazy quantifier (the extra "?")](http://www.regular-
expressions.info/repeat.html#lazy) to allow the optional `"***"` at the end to
match.

* * *

> **QUESTION 2** : How would the regexp groups allow me to ID section or sub
> section (possibly based on the number of /content in a match.group)?

The above regex captures _Sections_ only in group 1, and _Sub-Sections_ only
in group 2. And to make it easier to identify in the code, I'll use
[`(?P<named> groups)`](http://www.regular-expressions.info/named.html) and
retrieve the captures with
**[`.groupdict()`](https://docs.python.org/2/library/re.html#re.MatchObject.groupdict)**.

### Code:

    
    
    import re
    
    data = """  *** Section with no sub section
      *** Section with sub section ***
               *** Sub Section ***
      *** Another section"""
    
    pattern = r'^[ ]{0,2}(?:[*]{3}[ ]?(?P<Section>.*?)|[ ]+[*]{3}[ ]?(?P<SubSection>.*?))(?:[ ]?[*]{3})?$'
    regex = re.compile(pattern, re.M)
    
    for match in regex.finditer(data):
        print(match.groupdict())
    
    ''' OUTPUT:
    {'Section': 'Section with no sub section', 'SubSection': None}
    {'Section': 'Section with sub section', 'SubSection': None}
    {'Section': None, 'SubSection': 'Sub Section'}
    {'Section': 'Another section', 'SubSection': None}
    '''
    

  * [ideone DEMO](http://ideone.com/9fRpY6)

Instead of printing the dict, to reference each _Section_ /_Subsection_ , you
can use one of the following:

    
    
    match.group("Section")
    match.group(1)
    match.group("SubSection")
    match.group(2)
    

