[risolto] Manipolazioni argomento macro

  • Creatore
    Topic
  • #121444
    MatteoF
    Partecipante
      Up
      0
      Down
      ::


      Buongiorno a tutti,
      avrei due esigenze, riguardanti l’analisi / manipolazione di una stringa di testo.

      1) vorrei sapere se esiste un condizionale (kernel [tt]LaTeX[/tt] o pacchetto esterno) che verifichi se l’argomento di una macro inizi o meno con una lettera maiuscola.

      2) inoltre, ho la necessità di rimuovere l’ultimo carattere dell’argomento di una macro, in modo tale che [tt]\foo{Hello World}[/tt] diventi [tt]Hello Worl[/tt].

      Grazie mille,
      Matteo

    Visualizzazione 9 filoni di risposte
    • Autore
      Risposte
      • #121445
        robitex
        Amministratore del forum
          Up
          0
          Down
          ::

          MatteoF” post=122011Buongiorno a tutti,
          avrei due esigenze, riguardanti l’analisi / manipolazione di una stringa di testo.

          1) vorrei sapere se esiste un condizionale (kernel [tt]LaTeX[/tt] o pacchetto esterno) che verifichi se l’argomento di una macro inizi o meno con una lettera maiuscola (TitleCase).

          2) inoltre, ho la necessità di rimuovere l’ultimo carattere dell’argomento di una macro, in modo tale che [tt]\foo{Hello World}[/tt] diventi [tt]Hello Worl[/tt].

          Grazie mille,
          Matteo

          Ciao Matteo.
          Sicuramente si può fare con LaTeX. Sono comandi che puoi ottenere studiando la guida alla programmazione di Enrico. La trovi facilmente.
          Ti vorrei proporre la soluzione in Lua (e quindi dovrai passare a compilare con LuaLaTeX). Penso infatti che con questo genere di necessità alla fine Lua è preferibile perché certamente nasce sempre qualche nuova esigenza più facilmente implementabile.

          Per esempio: controllo se il primo carattere è maiuscolo:
          `% !TeX program = LuaLaTeX

          \documentclass{article}

          \directlua{
          myLib = {}
          function myLib.checkUppercase(s)
          assert(type(s)==[[string]])
          local code = string.byte(s, 1)
          if code > 64 and code < 91 then return true else return false end end } \newcommand{\isUpper}[1]{\directlua{ local s = [==[#1]==] if myLib.checkUppercase(s) then tex.sprint[[yes]] else tex.sprint[[no]] end }} \begin{document} \isUpper{rrr} \isUpper{L} \end{document}` Ciao. R.

        • #121446
          MatteoF
          Partecipante
            Up
            0
            Down
            ::


            Ciao Roberto,
            grazie mille per la tua proposta in linguaggio [tt]Lua[/tt]. Pur non conoscendo la programmazione, sono riuscito ad adattare il codice al mio caso d’uso:
            `
            \directlua{
            myLib = {}
            function myLib.checkUppercase(s)
            assert(type(s)==[[string]])
            local code = string.byte(s, 1)
            if code > 64 and code < 91 then return false else return true end end } \newcommand{\checkuppercase}[1]{% \directlua{ local s = [==[#1]==] if myLib.checkUppercase(s) then tex.sprint[==[\noindent]==] end} } ` Il tutto funziona, però la tua funzione [tt]myLib.checkUppercase(s)[/tt] ha dei limiti abbastanza importanti. Ovvero: funziona solamente con caratteri ASCII. Quindi fallisce con accenti e segni diacritici :( ` % !TeX program = LuaLaTeX \documentclass{article} \directlua{ myLib = {} function myLib.checkUppercase(s) assert(type(s)==[[string]]) local code = string.byte(s, 1) if code > 64 and code < 91 then return true else return false end end } \newcommand{\isUpper}[1]{\directlua{ local s = [==[#1]==] if myLib.checkUppercase(s) then tex.sprint[[yes]] else tex.sprint[[no]] end }} \begin{document} \isUpper{è} \isUpper{È} \end{document} ` Matteo

          • #121447
            OldClaudio
            Partecipante
              Up
              0
              Down
              ::


              Matteo, non sono abbastanza competente per esprimere pareri validi né sul codice Lua ti ti ha mandato Roberto né sulle funzioni per la manipolazione delle token list del linguaggio LaTeX; trovi le istruzioni nel capitolo 15 del manuale interface2 che puoi leggere con texdoc interface3.
              In questo capitolo ci sono “funzioni” sia per esamirare il primo token sia per capovolgere la lisa in modo da poter esaminare l’ultimo token della lista originale che è diventato il primo della lista capovolta;
              Nel capitolo 16 si parla delle strings, ma queste sono token list che NON contengono lettere ma solo caratteri analfabetici e spazi, mentre le token list possono contenere qualsiasi token, comprese le lettere.
              Se non vado errato Enrico scrisse un articolo sulle manipolazioni delle token list e delle cose incredibili che si possono fare con queste cose; di dovrebbe trovare su Ars di qualche anno fa. Lo puoi tovare esaminando la sezione ArsTeXnica di questo forum. Non sono sicuro se mostrasse come si esamina lo stato uppercase rispetto allo stato lower case. Comunque LaTeX3 è capce di manipolare tutti i caratteri, anche quelli non ASCII,

              Se ti immergi in LATeX3, scopri un mondo incredibilmente diverso da quanto siamo abituati a fare con LaTeX2e.

              Per me, visto che i miei neuroni cominciano a fare cilecca, LaTeX3 rimane un sogno, sebbene ne abbia usato molto, o meglio, molte inerfacce fal LaTeX2e e LaTeX3 che permettono di mantenere più o meno lo stesso approccio grammaticale al linguaggio interpretabile dall sottostante interprete.

            • #121448
              robitex
              Amministratore del forum
                Up
                0
                Down
                ::

                MatteoF” post=122019Ciao Roberto,
                grazie mille per la tua proposta in linguaggio [tt]Lua[/tt]. Pur non conoscendo la programmazione, sono riuscito ad adattare il codice al mio caso d’uso:
                `
                \directlua{
                myLib = {}
                function myLib.checkUppercase(s)
                assert(type(s)==[[string]])
                local code = string.byte(s, 1)
                if code > 64 and code < 91 then return false else return true end end } \newcommand{\checkuppercase}[1]{% \directlua{ local s = [==[#1]==] if myLib.checkUppercase(s) then tex.sprint[==[\noindent]==] end} } ` Il tutto funziona, però la tua funzione [tt]myLib.checkUppercase(s)[/tt] ha dei limiti abbastanza importanti. Ovvero: funziona solamente con caratteri ASCII. Quindi fallisce con accenti e segni diacritici :( ` % !TeX program = LuaLaTeX \documentclass{article} \directlua{ myLib = {} function myLib.checkUppercase(s) assert(type(s)==[[string]]) local code = string.byte(s, 1) if code > 64 and code < 91 then return true else return false end end } \newcommand{\isUpper}[1]{\directlua{ local s = [==[#1]==] if myLib.checkUppercase(s) then tex.sprint[[yes]] else tex.sprint[[no]] end }} \begin{document} \isUpper{è} \isUpper{È} \end{document} ` Matteo

                Ciao Matteo.
                Infatti è proprio così. Volevo solo darti uno spunto. Non mi intendo di Unicode così da poterti dare la soluzione. So che all’interno di LuaTeX ci si può avvalere di libreria utf8 con cui puoi manipolare anche stringhe unicode (pagina 63 del manuale “Multibyte string functions”).
                Penso anch’io che LaTeX3 possa risolvere i tuoi problemi di elaborazione stringhe come giustamente ha ricordato Claudio.
                Tuttavia nella mia esperienza capita che prima o poi il codice vada potenziato per nuove esigenze e che con Lua lo puoi fare con meno limitazioni.
                R.

              • #121449
                MatteoF
                Partecipante
                  Up
                  0
                  Down
                  ::

                  OldClaudio” post=122021Se ti immergi in LATeX3, scopri un mondo incredibilmente diverso da quanto siamo abituati a fare con LaTeX2e.

                  È da qualche settimana che ho iniziato a “giocherellare” con LaTeX3/expl3. Ho sempre seguito con interesse l’evoluzione di LaTeX (da ultimo il progetto Tagged PDF), cercando sempre di sfruttarne le potenzialità (al limite, ovviamente, delle mie capacità TeXniche e delle mie necessità pratiche).

                  Riguardo l’esigenza di una funzione che verifichi il case della prima lettera di un testo, ho trovato qualcosa di simile su tex.stackexchange. Modificando opportunamente la macro, ecco pronto il mio bel condizionale:
                  `
                  \prg_new_protected_conditional:Npnn \my_if_first_uppercase:n #1 { T , F , TF }
                  {
                  \tl_set:Nx \l_my_testa_tl { \tl_item:nn { #1 } { 1 } }
                  \tl_set:Nx \l_my_testb_tl { \exp_args:NV \text_uppercase:n \l_my_testa_tl }
                  \tl_if_eq:NNTF \l_my_testa_tl \l_my_testb_tl
                  { \prg_return_true: }
                  { \prg_return_false: }
                  }
                  `
                  La logica è la seguente: confrontare la variabile che memorizza la prima lettera di una stringa con la variabile che memorizza la stessa lettera in maiuscolo. Se le due variabili coincidono significa che la prima lettera della stringa è essa stessa una lettera maiuscola ([tt]true[/tt]), diversamente significa che la stringa inizia con una lettera minuscola ([tt]false[/tt]).

                  Di seguito un banale esempio del suo utilizzo:
                  `
                  \documentclass{minimal}

                  \ExplSyntaxOn
                  \prg_new_protected_conditional:Npnn \my_if_first_uppercase:n #1 { T , F , TF }
                  {
                  \tl_set:Nx \l_my_testa_tl { \tl_item:nn { #1 } { 1 } }
                  \tl_set:Nx \l_my_testb_tl { \exp_args:NV \text_uppercase:n \l_my_testa_tl }
                  \tl_if_eq:NNTF \l_my_testa_tl \l_my_testb_tl
                  { \prg_return_true: }
                  { \prg_return_false: }
                  }
                  \NewDocumentCommand { \mytest } { m }
                  {
                  \my_if_first_uppercase:nTF {#1}
                  { La~parola~ \emph{#1} ~inizia~con~una~lettera~ \text_uppercase:n {maiuscola}. }
                  { La~parola~ \emph{#1} ~inizia~con~una~lettera~minuscola. }
                  }
                  \ExplSyntaxOff

                  \begin{document}
                  \mytest{übersetzung}

                  \mytest{Übersetzung}
                  \end{document}
                  `
                  Per quanto riguarda la mia seconda esigenza (eliminazione dell’ultimo carattere di una stringa) avevo già letto gli «Appunti di programmazione in LaTeX e TeX» di Enrico Gregorio. Effettivamente sono presenti alcuni esempi sul genere (§ 7.2 Trattamento di liste di token in ε-TeX). Come potete immaginare: puro e crudo (e oscuro) linguaggio TeX.
                  Poco male: in [tt]interface3[/tt] (cap 15) ho già individuato le funzioni opportune… Stay tuned…

                  Matteo

                • #121450
                  MatteoF
                  Partecipante
                    Up
                    0
                    Down
                    ::


                    Riguardo l’eliminazione dell’ultimo carattere di una stringa, a partire da questo post sono riuscito a creare la seguente macro:
                    `
                    \cs_new_protected:Npn \my_remove_last:n #1
                    {
                    \tl_set:Nx \l_my_remove_last_tl { #1 }
                    \cs_generate_variant:Nn \tl_reverse:n {f}
                    \tl_set:Nx \l_my_remove_last_tl { \tl_reverse:f { \tl_tail:f { \tl_reverse:V \l_my_remove_last_tl } } }
                    \tl_use:N \l_my_remove_last_tl
                    }
                    `
                    Il comando [tt]\tl_tail[/tt] «discards all leading explicit space characters (explicit tokens with character code 32 and category code 10) and the first ⟨item⟩ in the ⟨token list⟩, and leaves the remaining tokens in the input stream» ([tt]interface3[/tt], p. 114). Poco male, nel mio caso d’uso la stringa di testo è una singola parola:
                    `
                    \documentclass{minimal}

                    \ExplSyntaxOn
                    \cs_new_protected:Npn \my_remove_last:n #1
                    {
                    \tl_set:Nx \l_my_remove_last_tl { #1 }
                    \cs_generate_variant:Nn \tl_reverse:n {f}
                    \tl_set:Nx \l_my_remove_last_tl { \tl_reverse:f { \tl_tail:f { \tl_reverse:V \l_my_remove_last_tl } } }
                    \tl_use:N \l_my_remove_last_tl
                    }
                    \NewDocumentCommand { \mytest } { m }
                    {
                    \my_remove_last:n {#1}
                    }
                    \ExplSyntaxOff

                    \begin{document}
                    \mytest{ciao}
                    \end{document}
                    `
                    Matteo

                  • #121451
                    OldClaudio
                    Partecipante
                      Up
                      0
                      Down
                      ::


                      Ottimo, bravo Matteo!

                      Ero sicuro che con LaTeX 3 ce l’avresti fatta.

                    • #121452
                      Up
                      0
                      Down
                      ::

                      MatteoF” post=122011Buongiorno a tutti,
                      avrei due esigenze, riguardanti l’analisi / manipolazione di una stringa di testo.

                      1) vorrei sapere se esiste un condizionale (kernel [tt]LaTeX[/tt] o pacchetto esterno) che verifichi se l’argomento di una macro inizi o meno con una lettera maiuscola.

                      2) inoltre, ho la necessità di rimuovere l’ultimo carattere dell’argomento di una macro, in modo tale che [tt]\foo{Hello World}[/tt] diventi [tt]Hello Worl[/tt].

                      Grazie mille,
                      Matteo

                      Dipende molto da che cosa si intende passare. Se è testo arbitrario in UTF-8 in pdflatex, è piuttosto complesso, ma fattibile. Se assumiamo XeLaTeX o LuaLaTeX, è molto più semplice.
                      `
                      \prg_new_conditional:Nnn \matteo_if_firstchar_uc:n { p,T,F,TF }
                      {
                      \str_if_eq:eeTF { \str_head:e { \str_uppercase:n { #1 } } } { \str_head:n { #1 } } { \prg_return_true: } { \prg_return_false: }
                      }
                      \cs_generate_variant:Nn \str_head:n { e }

                      \cs_new:Nn \matteo_remove_last_char:n
                      {
                      \tl_range:nnn { #1 } { 1 } { -2 }
                      }
                      `

                      Differenze con il tuo codice? Che il condizionale è espandibile, così come la rimozione dell’ultimo carattere.

                      Esempio completo:

                      `
                      \documentclass{article}

                      \ExplSyntaxOn

                      \prg_new_conditional:Nnn \matteo_if_firstchar_uc:n { p,T,F,TF }
                      {
                      \str_if_eq:eeTF
                      { \str_head:e { \str_uppercase:n { #1 } } }
                      { \str_head:n { #1 } }
                      { \prg_return_true: }
                      { \prg_return_false: }
                      }
                      \cs_generate_variant:Nn \str_head:n { e }

                      \cs_new:Nn \matteo_remove_last_char:n
                      {
                      \tl_range:nnn { #1 } { 1 } { -2 }
                      }

                      \NewDocumentCommand{\testUC}{mmm}
                      {
                      \matteo_if_firstchar_uc:nTF { #1 } { #2 } { #3 }
                      }

                      \NewExpandableDocumentCommand{\testremove}{m}
                      {
                      \matteo_remove_last_char:n { #1 }
                      }

                      \ExplSyntaxOff

                      \begin{document}

                      \testUC{Hello World}{VERO}{FALSO}

                      \testUC{hello world}{VERO}{FALSO}

                      \testremove{Hello World}

                      \end{document}
                      `

                      Ciao
                      Enrico

                    • #121453
                      Up
                      0
                      Down
                      ::


                      [tt]\cs_generate_variant:Nn[/tt] NON va nella definizione, ma fuori.

                      Ciao
                      Enrico

                    • #121454
                      MatteoF
                      Partecipante
                        Up
                        0
                        Down
                        ::


                        Grazie mille per i chiarimenti!

                        Matteo

                    Visualizzazione 9 filoni di risposte
                    • Devi essere connesso per rispondere a questo topic.

                    Go to top