[C++] Da $ a \(

Messaggioda marco2132k » 27/08/2022, 13:21

Ciao. Volevo scrivere una funzione latex2e_fy che data una stringa come
Codice:
Sia $ G $ un gruppo.
ritornasse la stringa
Codice:
Sia \( G \) un gruppo.


Non so bene come fare. Ho scritto un prototipo che produce
Codice:
Sia ( G ) un gruppo.
perché non so bene come trattare i due caratteri di \(.

Inoltre conosco pochissimo il linguaggio e non ho idea se quello che ho scritto è buon codice (in particolare se avete voglia di spiegarmi come si potrebbe fare una cosa del genere in C++ moderno ciò è molto ben accetto).

Codice:
#include <iostream>
#include <string>

std::string latex2e_fy(std::string s) {
    bool d = false;
    for(std::string::iterator c = s.begin(); c != s.end(); ++c) {
        if(*c == '$' && d == false) {
            d = true;
            *c = '(';
        }
        if(*c == '$' && d == true) {
            *c = ')';
            d = false;
        }
    }
   
    return s;
}

int main() {
    std::cout << latex2e_fy("Sia $ G $ un gruppo.");
    return 0;
}


Come bonus: come si potrebbe fare una cosa del genere in (buon) Python (3)?
marco2132k
Advanced Member
Advanced Member
 
Messaggio: 1055 di 2053
Iscritto il: 18/02/2018, 23:52

Re: [C++] Da $ a \(

Messaggioda megas_archon » 27/08/2022, 13:51

Anche tu lo odi quando devi scrivere qui, vero?

Se usi vim fai come me: installa Ultisnips https://github.com/SirVer/ultisnips e poi definisci uno snippet così:
Codice:
snippet '\$(.+?)\$' "mentify text" wrA
\(`!p snip.rv = match.group(1)`\)
endsnippet
(questo è anche la risposta alla domanda bonus, perché stai usando una regex e del pyhton basilare per trasformare ogni gruppo $culo$ in \(culo\) mentre scrivi).


PS: C++? A meno che tu non debba programmare un videogioco o un semaforo, eviterei.
Avatar utente
megas_archon
Senior Member
Senior Member
 
Messaggio: 427 di 1318
Iscritto il: 13/06/2021, 20:57

Re: [C++] Da $ a \(

Messaggioda utente__medio » 27/08/2022, 15:47

Ciao.

- se ho ben capito vuoi che le sottostringhe
Codice:
$ "something" $

siano sostituite con
Codice:
\( "something" \)

, giusto?

- il carattere $ può comparire nella stringa solo con l'accezione sopra evidenziata?

- la stringa in input può essere ritenuta sintatticamente corretta oppure andrebbe comunque controllata?
"Ci abbaiano, Sancho; segno che stiamo cavalcando!"
utente__medio
Junior Member
Junior Member
 
Messaggio: 175 di 394
Iscritto il: 02/11/2021, 12:48
Località: Draghistan

Re: [C++] Da $ a \(

Messaggioda marco2132k » 27/08/2022, 19:38

megas_archon ha scritto:Anche tu lo odi quando devi scrivere qui, vero?
Ahah sì, ma almeno i \(, \) sono LaTeX standard.

Comunque volevo solo vedere se mi ricordavo come si scrivevano due righe di codice. Credo che si potesse fare anche con una cosa come https://www.gnu.org/software/emacs/manu ... place.html, ma la voglia di imparare le regex oggi non c'è.

@utente_medio Rispondo "Sì" a tutte le tue domande, anche se ovviamente non ho un'idea ben precisa di come dovrebbe essere fatta una stringa ben formata.

megas_archon ha scritto:PS: C++? A meno che tu non debba programmare un videogioco o un semaforo, eviterei.
Oddio, assieme alla STL non è meno scriptabile di Python. Credo che in un linguaggio tipo Haskell invece la soluzione sia uno one-liner...
marco2132k
Advanced Member
Advanced Member
 
Messaggio: 1056 di 2053
Iscritto il: 18/02/2018, 23:52

Re: [C++] Da $ a \(

Messaggioda megas_archon » 27/08/2022, 19:49

Ma anche in bash è uno oneliner, eh...
Avatar utente
megas_archon
Senior Member
Senior Member
 
Messaggio: 429 di 1318
Iscritto il: 13/06/2021, 20:57

Re: [C++] Da $ a \(

Messaggioda megas_archon » 27/08/2022, 20:01

Adesso non ho tempo di scrivere tutto per bene, ma quello che vuoi è parsare il tuo file cercando cose del tipo \$[^\$\n]{1,}\n e alzando un errore se ce ne sono: se ce ne sono significa che c'è una cosa del genere
Codice:
$matematica bellissima ma
dollari che non matchano$

e una regex "stupida" non può gestire queste situazioni.
Quindi, come si fa questo in python? Non lo so, ma non penso sia molto diverso da un try-catch con un messaggio di errore personalizzato...

Quindi è meglio vietarle all'origine e chiedere all'user (tu o altri) di presentare solo un file dove il dollaro "che apre" e quello "che chiude" sono sulla stessa riga.

Fatto questo, la regex è la stessa, cerchi \$(.+?)\$ e vuoi sostituirlo con \($1\). A seconda del linguaggio in cui scrivi cambiano le wildcards delle espressioni regolari e anche il modo specifico di implementarli (e.g. dove stanno di preciso i gruppi che la regex catcha) quindi non provo nemmeno a farlo oggi, tanto piu che sta saltando la luce ogni dieci minuti...
Avatar utente
megas_archon
Senior Member
Senior Member
 
Messaggio: 430 di 1318
Iscritto il: 13/06/2021, 20:57

Re: [C++] Da $ a \(

Messaggioda utente__medio » 27/08/2022, 20:12

marco2132k ha scritto:@utente_medio Rispondo "Sì" a tutte le tue domande

In tal caso penso che qualcosa del genere potrebbe andare:
Codice:
#include <iostream>
#include <string>

using namespace std;

string fun(const string &s_in)
{
    string s_out;
    for(unsigned int flag = false, i = 0; i < s_in.size(); ++i)
    {
        if(s_in[i] == '$')
        {
            s_out.push_back('\\');
            s_out.push_back((flag = !flag) ? '(' : ')');
        }
        else
        {
            s_out.push_back(s_in[i]);
        }
    }
    return s_out;
}

int main()
{
    cout << fun("Sia $ G $ un gruppo.") << endl;
}
"Ci abbaiano, Sancho; segno che stiamo cavalcando!"
utente__medio
Junior Member
Junior Member
 
Messaggio: 178 di 394
Iscritto il: 02/11/2021, 12:48
Località: Draghistan

Re: [C++] Da $ a \(

Messaggioda megas_archon » 27/08/2022, 20:57

Codice:
import re

pattern = re.compile("\$[^\$\n]{1,}\n")

for i, line in enumerate(open('cose.txt')):
    for match in re.finditer(pattern, line):
        print( 'Unmatched dollar before newline on line %s: %s' % (i+1, match.group()))

Questo serve a trovare i dollari solitari. Ovviamente si può fare di meglio:

- dando contesto all'utente (printa la riga del match, la precedente, e la successiva)
- colorando il match di rosso

ma adesso ho voglia zero. Il resto è banale, e in effetti è uno script che già ho: adattalo da qui

Codice:
#!/usr/bin/env python3
import re, os, sys

good_delims = lambda x: re.sub(r"\$(.*?)\$", r"\\(\1\\)", x, flags = re.M)

with open (sys.argv[1], 'r+' ) as f:
    content = f.read()
    content = good_delims(content)
    f.seek(0)
    f.write(content)
    f.truncate()

os.system("latexindent -w " + sys.argv[1])

Fammi sapere se funonzia.
Avatar utente
megas_archon
Senior Member
Senior Member
 
Messaggio: 431 di 1318
Iscritto il: 13/06/2021, 20:57

Re: [C++] Da $ a \(

Messaggioda marco2132k » 27/08/2022, 23:17

megas_archon ha scritto:[È] meglio vietarle all'origine e chiedere all'user (tu o altri) di presentare solo un file dove il dollaro "che apre" e quello "che chiude" sono sulla stessa riga.
In teoria se la stringa è "ben formata" (cioè è del LaTeX scritto nella vita reale) una cosa del genere può capitare solo se l'editor fa hard wrapping, no?

Poi provo se quello che hai scritto tu funzia ma faccio un po' fatica a capire cosa fa (perché non conosco bene né Python né appunto le regex).

@utente_medio Leggendo il tuo snippet mi è venuto in mente che la mia latex2e_fy ha side effects. Ci riprovo.

Codice:
#include <fstream>
#include <iostream>
#include <string>

std::string latex2e_fy(const std::string& s_in) {
  bool d = false;

  std::string s_out;
  s_out.reserve(s_in.length());

  for(auto c : s_in) {
    if(c == '$' && d == false) {
      s_out.append("\\(");
      d = !d;
    }
    else if (c == '$' && d == true) {
      s_out.append("\\)");
      d = !d;
    }
    else {
      s_out.push_back(c);
    }
  }
  return s_out;
}

int main(int argc, char** argv) {
  if(argc < 3) {
    std::cout << "Utilizzo: latex2e_fy input file output file.";
    return 1;
  }

  std::ifstream f_in(argv[1]);
  std::ofstream f_out(argv[2]);

  if(f_in.is_open() && f_out.is_open()) {
    std::string current_line;
    while(std::getline(f_in,current_line)) {
      f_out << latex2e_fy(current_line) << std::endl;
    }
  }

  f_in.close();
  f_out.close();

  return 0;
}


Questo apparentemente funzia.

Domanda: ho pensato di usare reserve per migliorare le prestazioni. E invece le peggiora. Come mai?
marco2132k
Advanced Member
Advanced Member
 
Messaggio: 1057 di 2053
Iscritto il: 18/02/2018, 23:52

Re: [C++] Da $ a \(

Messaggioda kaspar » 28/08/2022, 15:25

Testo nascosto, perché contrassegnato dall'autore come fuori tema. Fai click in quest'area per vederlo.
Tipicamente, questa roba è da Perl. Ad esempio:
Codice:
#!/usr/bin/env perl -w

# usage: $ ./this-script.pl < input.tex > output.tex

my $delim = "\\("; my $line;

while ($line = <STDIN>) {
  while ($line =~ /[^\\]\$/) {
    $line =~ s/([^\\])\$/$1$delim/;
    $delim = $delim eq "\\(" ? "\\)" : "\\(";
  }
  print $line;
}

In Haskell comunque non è complicato: con interact si può fare qualcosa di decente...
kaspar
Junior Member
Junior Member
 
Messaggio: 254 di 495
Iscritto il: 17/11/2019, 09:58

Prossimo

Torna a Informatica

Chi c’è in linea

Visitano il forum: Nessuno e 1 ospite