简体   繁体   中英

Extracting text from a .tex document with Python regular expressions

I'm attemping to retrieve a bunch a text from a LaTeX file, that consists of blocks like

\newcommand{\lhaac}{% 2
Olkoot tapahtumat A = 'kortti on musta', B = 'kortti on hertta' ja 
C = 'kortti on kuvakortti tai ässä'. Lausu seuraavat tapahtumat joukkojen A,B ja C sekä joukko-operaatioiden avulla\\% ja laske todennäköisyydet  \\
        \textbf{a)}     Kortti on musta kuvakortti tai musta ässä\\
        \textbf{b)} Kortti on ruutu\\
        \textbf{c)} Kortti ei ole ruutu, mutta se on kuva tai ässä\\
        \textbf{d)} Kortti on joko punainen tai se on arvoltaan 2-10, mutta ei molempia

}
%__________
\newcommand{\lhaacv}{%
a) Kortti on musta kuvakortti tai musta ässä = Kortti on musta ja kortti on kuvakortti tai  ässä: $A\cap C$,\\  
b) Kortti on ruutu = kortti ei musta ja ei hertta: $\overline{A}\cap\overline{B} = \overline{A\cup B}$\\
c) (Kortti on musta tai hertta) ja kortti on  kuva tai ässä:\\ $(A\cup B)\cap C = (A\cap C)\cup (B\cap C)$ \\ 
d) Kortti on punainen kuvakortti tai musta pikkukortti:\\ $(\overline{A}\cap C)\cup (A\cap \overline{C}) = (\overline{A}\cup \overline{C})\backslash (\overline{A}\cap \overline{C})$

}

Using re.findall , I would like to gain access to the 3-letter code immediately succeeding \\lh in each command, and the command contents or definitions, meaning the entire blocks of text contained between the braces after the command name definition.

Parsing the 3-letter code is not an issue, but simply gaining access to all of the contents of \\newcommand{\\lhaac}{<contents>} is proving to be difficult, since LaTeX source can contain braces and backslashes and other nasty things, making it difficult to express how contents I want to access actually end (because a brace ends a command definition). The comment lines

%__________

can not be trusted to exist after every command.

I've tried this and this , for starters. In the first case, the matching stops after the first } encountered, while in the second example pretty much everything after the beginning { is matched, just as expected. Attempting something more complicated like this seems to work on a simple test case, but entering an actual block found in the file produces no match.

I'm therefore asking for help in cracking this puzzle. I can't seem to see what I'm missing here. In the last case, I think I've covered normal text, math (both inline $<math here>$ and display $$<math here>$$ ), and commands ( \\<command name>[<optional argument>]{<mandatory argument>} ) with and without arguments. Environments, such as

\begin{<environment name>}[<optional argument>]{<mandatory argument>}
  <contents>
\end{<environment name>} 

are still missing, but those can be easily covered later.

As per re.findall documentation , it should return a list of tuples (since I have multiple capturing groups in the regex), with the 3-letter code as the first and the command contents as the second element of each tuple. In this case the first tuple (contained in a list) returned would be

[("aac", "% 2
Olkoot tapahtumat A = 'kortti on musta', B = 'kortti on hertta' ja 
C = 'kortti on kuvakortti tai ässä'. Lausu seuraavat tapahtumat joukkojen A,B ja C sekä joukko-operaatioiden avulla\\% ja laske todennäköisyydet  \\
        \textbf{a)}     Kortti on musta kuvakortti tai musta ässä\\
        \textbf{b)} Kortti on ruutu\\
        \textbf{c)} Kortti ei ole ruutu, mutta se on kuva tai ässä\\
        \textbf{d)} Kortti on joko punainen tai se on arvoltaan 2-10, mutta ei molempia

")]

Here You go:

=^..^=

import re

raw_string = """\newcommand{\lhaac}{% 2
Olkoot tapahtumat A = 'kortti on musta', B = 'kortti on hertta' ja 
C = 'kortti on kuvakortti tai ässä'. Lausu seuraavat tapahtumat joukkojen A,B ja C sekä joukko-operaatioiden avulla\\% ja laske todennäköisyydet  \\
        \textbf{a)}     Kortti on musta kuvakortti tai musta ässä\\
        \textbf{b)} Kortti on ruutu\\
        \textbf{c)} Kortti ei ole ruutu, mutta se on kuva tai ässä\\
        \textbf{d)} Kortti on joko punainen tai se on arvoltaan 2-10, mutta ei molempia

}
%__________
\newcommand{\lhaacv}{%
a) Kortti on musta kuvakortti tai musta ässä = Kortti on musta ja kortti on kuvakortti tai  ässä: $A\cap C$,\\  
b) Kortti on ruutu = kortti ei musta ja ei hertta: $\overline{A}\cap\overline{B} = \overline{A\cup B}$\\
c) (Kortti on musta tai hertta) ja kortti on  kuva tai ässä:\\ $(A\cup B)\cap C = (A\cap C)\cup (B\cap C)$ \\ 
d) Kortti on punainen kuvakortti tai musta pikkukortti:\\ $(\overline{A}\cap C)\cup (A\cap \overline{C}) = (\overline{A}\cup \overline{C})\backslash (\overline{A}\cap \overline{C})$

}
%__________
"""

remove_command = re.sub(r'\newcommand{\\', '', raw_string)
codes = re.findall('lh\w+', remove_command)

part_1 = []
for item in codes:
    part_1.append(item[2::])


result2 = re.findall(r'{.*?}\n%_+', remove_command, re.DOTALL)
part_2 = []
for item in result2:
    clean_1 = re.sub(r'{%', '', item)
    clean_2 = re.sub(r'\n}\n%_+', '', clean_1)
    part_2.append(clean_2)


result = zip(part_1, part_2)

Output:

aac
 2
Olkoot tapahtumat A = 'kortti on musta', B = 'kortti on hertta' ja 
C = 'kortti on kuvakortti tai ässä'. Lausu seuraavat tapahtumat joukkojen A,B ja C sekä joukko-operaatioiden avulla\% ja laske todennäköisyydet  \
            extbf{a)}     Kortti on musta kuvakortti tai musta ässä\
            extbf{b)} Kortti on ruutu\
            extbf{c)} Kortti ei ole ruutu, mutta se on kuva tai ässä\
            extbf{d)} Kortti on joko punainen tai se on arvoltaan 2-10, mutta ei molempia

------------------------------------------------------------------------------------------------------------------------------------------------------
aacv

a) Kortti on musta kuvakortti tai musta ässä = Kortti on musta ja kortti on kuvakortti tai  ässä: $A\cap C$,\  
b) Kortti on ruutu = kortti ei musta ja ei hertta: $\overline{A}\cap\overline{B} = \overline{A\cup B}$\
c) (Kortti on musta tai hertta) ja kortti on  kuva tai ässä:\ $(A\cup B)\cap C = (A\cap C)\cup (B\cap C)$ \ 
d) Kortti on punainen kuvakortti tai musta pikkukortti:\ $(\overline{A}\cap C)\cup (A\cap \overline{C}) = (\overline{A}\cup \overline{C}ackslash (\overline{A}\cap \overline{C})$

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM