How to extract content between a prefix and a suffix?
<p>I want to extract text from {inside} the curly brackets. The differences between those texts are the prefixes, such as <code>\section{</code> or <code>\subsection{</code> to categorize everything accordingly. And every end needs to be set by the next closed curly bracket <code>}</code>.</p>

<pre><code>file = "This is a string of an \section{example file} used for \subsection{Latex} documents."

# These are some Latex commands to be considered:

heading_1 = "\\\\section{"
heading_2 = "\\\\subsection{"

# This is my attempt.

for letter in file:
    print("The current letter: " + letter + "\n")
</code></pre>

<p>I want to process a Latex file by using Python to convert it for my database.</p>

<p>If you just want the pairs <code>(section-level, title)</code> for all the file you can use a simple regex:</p>

<pre><code>import re

codewords = [
    'section',
    'subsection',
    # add other here if you want to
]

regex = re.compile(r'\\({})\{{([^}}]+)\}}'.format('|'.join(re.escape(word) for word in codewords)))
</code></pre>

<p>Sample usage:</p>

<pre><code>In [15]: text = '''
    ...: \section{First section}
    ...: 
    ...: \subsection{Subsection one}
    ...: 
    ...: Some text
    ...: 
    ...: \subsection{Subsection two}
    ...: 
    ...: Other text
    ...: 
    ...: \subsection{Subsection three}
    ...: 
    ...: Some other text
    ...: 
    ...: 
    ...: Also some more text \texttt{other stuff}
    ...: 
    ...: \section{Second section}
    ...: 
    ...: \section{Third section}
    ...: 
    ...: \subsection{Last subsection}
    ...: '''

In [16]: regex.findall(text)
Out[16]: 
[('section', 'First section'),
 ('subsection', 'Subsection one'),
 ('subsection', 'Subsection two'),
 ('subsection', 'Subsection three'),
 ('section', 'Second section'),
 ('section', 'Third section'),
 ('subsection', 'Last subsection')]
</code></pre>

<p>By changing the value of the <code>codewords</code> list you'll be able to match more kind of commands.</p>

<p>To apply this to a file simply <code>read()</code> it first:</p>

<pre><code>with open('myfile.tex') as f:
    regex.findall(f.read())
</code></pre>

<p>If you have the guarantee that all those commands are on the same line then you can be more memory efficient and do:</p>

<p>with open('myfile.tex') as f:
    results = []
    for line in f:
        results.extends(regex.findall(line))</p>

<p>Or if you want to be a bit more fancy:</p>

<pre><code>from itertools import chain

with open('myfile.tex') as f:
    results = chain.from_iterable(map(regex.findall, f))
</code></pre>

<p>Note however that if you have something like:</p>

<pre><code>\section{A very 
    long title}
</code></pre>

<p>This will fail, why the solution using <code>read()</code> will get that section too.</p>

<hr>

<p>In any case you have to be aware that the slightest change in format will break these kind of solutions. As such for a safer alternative you'll have to look for a proper LaTeX parser.</p>

<hr>

<p>If you want to group together the subsections "contained" in a given section you can do so after obtaining the result with the above solution. You have to use something like <code>itertools.groupby</code>.</p>

<p>from itertools import groupby, count, chain</p>

<pre><code>results = regex.findall(text)

def make_key(counter):
    def key(match):
        nonlocal counter
        val = next(counter)
        if match[0] == 'section':
            val = next(counter)
        counter = chain([val], counter)
        return val
    return key

organized_result = {}

for key, group in groupby(results, key=make_key(count())):
    _, section_name = next(group)
    organized_result[section_name] = section = []
    for _, subsection_name in group:
        section.append(subsection_name)
</code></pre>

<p>And the final result will be:</p>

<pre><code>In [12]: organized_result
Out[12]: 
{'First section': ['Subsection one', 'Subsection two', 'Subsection three'],
 'Second section': [],
 'Third section': ['Last subsection']}
</code></pre>

<p>Which matches the structure of the text at the beginning of the post.</p>

<p>If you want to make this extensible using the <code>codewords</code> list things will get quite a bit more complex. </p>

python latex