Un carattere alla volta reso maiuscolo

  • Creatore
    Topic
  • #59571
    robitex
    Amministratore del forum
      Up
      0
      Down
      ::


      Sto mettendo a punto un comando per disegnare il barcode con codifica code39 di una stringa. Il comando deve selezionare della stringa un carattere alla volta ed in questo caso ci risco con:
      `\documentclass{minimal}
      \makeatletter

      \def\makeup#1{%
      \parsechar#1\@nil
      }

      \def\parsechar#1#2\@nil{%
      #1\\
      \def\temp{#2}
      \ifx\temp\empty
      \else
      \parsechar#2\@nil
      \fi
      }

      \makeatother

      \begin{document}
      \noindent\makeup{12q\$wert\%y+-}

      \end{document}`

      Tuttavia se provo a rendere maiuscoli i caratteri (il code39 accetta solo caratteri maiuscoli), il codice non funziona più:
      `% non funziona
      \documentclass{minimal}

      \makeatletter

      \def\makeup#1{%
      \expandafter\parsechar\uppercase{#1}\@nil
      }

      \def\parsechar#1#2\@nil{%
      #1\\
      \def\temp{#2}
      \ifx\temp\empty
      \else
      \parsechar#2\@nil
      \fi
      }
      \makeatother

      \begin{document}
      \noindent\makeup{12q\$wert\%y+-}
      \end{document}`

      Eppure l’effetto del primo \expandafter dovrebbe essere quello di espandere \uppercase e restituire al comando delimitato i token dei caratteri semplici ma resi maiuscoli.
      L’errore è quello di un parentisi graffa aperta mancante.

      Ho provato anche a definire una macro \temp come \def\temp{\uppercase{#1}} ed espanderla dopo ma viene riportato lo stesso errore.
      Grazie per l’aiuto.
      R.

    Visualizzazione 5 filoni di risposte
    • Autore
      Risposte
      • #59572
        Up
        0
        Down
        ::

        Sto mettendo a punto un comando per disegnare il barcode con codifica code39 di una stringa. Il comando deve selezionare della stringa un carattere alla volta ed in questo caso ci risco con:
        `\documentclass{minimal}
        \makeatletter

        \def\makeup#1{%
        \parsechar#1\@nil
        }

        \def\parsechar#1#2\@nil{%
        #1\\
        \def\temp{#2}
        \ifx\temp\empty
        \else
        \parsechar#2\@nil
        \fi
        }

        \makeatother

        \begin{document}
        \noindent\makeup{12q\$wert\%y+-}

        \end{document}`

        Tuttavia se provo a rendere maiuscoli i caratteri (il code39 accetta solo caratteri maiuscoli), il codice non funziona più:
        `% non funziona
        \documentclass{minimal}

        \makeatletter

        \def\makeup#1{%
        \expandafter\parsechar\uppercase{#1}\@nil
        }

        \def\parsechar#1#2\@nil{%
        #1\\
        \def\temp{#2}
        \ifx\temp\empty
        \else
        \parsechar#2\@nil
        \fi
        }
        \makeatother

        \begin{document}
        \noindent\makeup{12q\$wert\%y+-}
        \end{document}`

        Eppure l’effetto del primo \expandafter dovrebbe essere quello di espandere \uppercase e restituire al comando delimitato i token dei caratteri semplici ma resi maiuscoli.
        L’errore è quello di un parentisi graffa aperta mancante.

        Ho provato anche a definire una macro \temp come \def\temp{\uppercase{#1}} ed espanderla dopo ma viene riportato lo stesso errore.
        Grazie per l’aiuto.
        R.

        \uppercase non è espandibile. Quando TeX trova \uppercase{}, interrompe ciò che sta facendo, converte i nell’equivalente maiuscolo (solo i caratteri espliciti) senza espandere nulla e rimette la lista di token ottenuta al posto di \uppercase{}. La soluzione è eseguire prima \uppercase:
        `\def\makeup#1{\uppercase{\parsechar#1\@nil}}`
        C’è un modo migliore di definire \parsechar:
        `\def\parsechar#1{%
        \ifx#1\@nil\else
        #1\\%
        \expandafter\parsechar
        \fi}`
        che effettivamente consuma un token alla volta, mentre la tua rilegge ogni volta tutto quanto rimane dopo ogni passaggio.

        Nel caso di \makeup{12q\$wert\%y+-}, dopo l’esecuzione di \uppercase ci troviamo
        `\parsechar 12Q\$WERT\%Y+-\@nil`
        e #1 è 1, che non è \@nil. Perciò ci si trova con
        `1\\\expandafter\parsechar\fi 2Q\$WERT\%Y+-\@nil`
        I token 1 e \\ vengono spediti avanti e viene espanso \expandafter che a sua volta espande \fi, la cui espansione è vuota! Dunque ci troviamo
        `\parsechar 2Q\$WERT\%Y+-\@nil`
        esattamente come voluto.

        Ovviamente se inserisci nell’argomento di \makeup comandi con argomento o comandi non definiti ti trovi nei pasticci, ma non credo sia un problema. Esercizio: perché, con la mia definizione, \makeup{abc\ddt xyz} non dà errore a \ddt ma a \@nil, mentre con la tua lo dà a \ddt?

        Ciao
        Enrico

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

          Esercizio: perché, con la mia definizione, \makeup{abc\ddt xyz} non dà errore a \ddt ma a \@nil, mentre con la tua lo dà a \ddt?

          Ciao
          Enrico

          Perché nella mia definizione \@nil è un token di delimitazione che non verrà mai espanso e quindi l’errore verrà provocato dall’espansione di \ddt.

          Nel tuo codice invece, tutto dipende dal condizionale \ifx:
          se \ifx si trova un carattere ed un token command sequence da confrontare darà come risultato falso senza espandere \@nil.
          Se invece deve operare su due cs come quando incontra \ifx\ddt\@nil allora deve indagarne il significato cominciando ad espandere il secondo che quindi solleverà l’errore.
          Giusto?
          R.

        • #59574
          Up
          0
          Down
          ::

          Esercizio: perché, con la mia definizione, \makeup{abc\ddt xyz} non dà errore a \ddt ma a \@nil, mentre con la tua lo dà a \ddt?

          Ciao
          Enrico

          Perché nella mia definizione \@nil è un token di delimitazione che non verrà mai espanso e quindi l’errore verrà provocato dall’espansione di \ddt.

          Nel tuo codice invece, tutto dipende dal condizionale \ifx:
          se \ifx si trova un carattere ed un token command sequence da confrontare darà come risultato falso senza espandere \@nil.
          Se invece deve operare su due cs come quando incontra \ifx\ddt\@nil allora deve indagarne il significato cominciando ad espandere il secondo che quindi solleverà l’errore.
          Giusto?

          Sbagliato. 🙂 La risposta riguardo la tua definizione è corretta. Con l’altro metodo a un certo punto TeX incontra \ifx\ddt\@nil e confronta i due token senza espanderli; ma li considera uguali perché entrambi sono indefiniti e quindi la ricorsione termina. Quando poi TeX trova il \@nil che è rimasto emette il messaggio di errore di “Undefined control sequence”.

          Se hai timore che nell’argomento di \makeup possano intrufolarsi token non definiti, è meglio usare come sentinella un token definito e inconsueto, per esempio \uchyph.

          Ciao
          Enrico

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

            [quote]Esercizio: perché, con la mia definizione, \makeup{abc\ddt xyz} non dà errore a \ddt ma a \@nil, mentre con la tua lo dà a \ddt?

            Ciao
            Enrico

            Perché nella mia definizione \@nil è un token di delimitazione che non verrà mai espanso e quindi l’errore verrà provocato dall’espansione di \ddt.

            Nel tuo codice invece, tutto dipende dal condizionale \ifx:
            se \ifx si trova un carattere ed un token command sequence da confrontare darà come risultato falso senza espandere \@nil.
            Se invece deve operare su due cs come quando incontra \ifx\ddt\@nil allora deve indagarne il significato cominciando ad espandere il secondo che quindi solleverà l’errore.
            Giusto?

            Sbagliato. 🙂 La risposta riguardo la tua definizione è corretta. Con l’altro metodo a un certo punto TeX incontra \ifx\ddt\@nil e confronta i due token senza espanderli; ma li considera uguali perché entrambi sono indefiniti e quindi la ricorsione termina. Quando poi TeX trova il \@nil che è rimasto emette il messaggio di errore di “Undefined control sequence”.

            Se hai timore che nell’argomento di \makeup possano intrufolarsi token non definiti, è meglio usare come sentinella un token definito e inconsueto, per esempio \uchyph.

            Ciao
            Enrico[/quote]

            Spiegazione completa a questo punto… grazie.
            Quello che manca è raccontare come è andata a finire la questione.
            Intanto ho adottato la soluzione di parsing a singolo carattere anche solo per aumentare l’efficienza (motivo del perché vorrei abbandonare la soluzione attuale basata su pstricks).

            Ecco come funziona il codice:
            ho creato 43 macro diverse ognuna per i 43 simboli che possono essere rappresentati da code39. Queste macro sono state nominate con \barchar@.
            Per esempio il carattere A è reso dalla macro \barchar@A, quindi quando la macro di parsing passa un singolo carattere costruisco la command sequence relativa per le cifre da 0 a 9 e per le 26 lettere.
            Se tale token non è vuoto (come nella maggioranza dei casi), allora produco il disegno corrispondente delle barre, altrimenti verifico che non sia uno dei simboli speciali, e se non sono in uno di questi casi emetto un messaggio d’errore. Ecco il codice:
            `
            % user interface macro
            \newcommand{\barcode}[1]{%
            \ifx#1\empty
            % package warning
            \else
            \barcode@Start
            \expandafter\uppercase\expandafter{\expandafter\barcode@parsechar#1\@nil}
            \barcode@Stop
            \fi
            }
            %
            \def\barcode@parsechar#1{%
            \ifx#1\@nil\else
            \def\tempsymb{*}
            \ifx#1\tempsymb
            % package error
            \fi
            % command sequence of the char
            \expandafter\let\expandafter\tempchar\csname barchar@#1\endcsname
            \ifx\tempchar\relax
            \ifx#1\space
            \barchar@space
            \barstep@interchar
            \else
            \def\tempsymb{-}
            \ifx#1\tempsymb
            \barchar@bar
            \barstep@interchar
            \else
            \def\tempsymb{.}
            \ifx#1\tempsymb
            \barchar@dot
            \barstep@interchar
            \else
            \def\tempsymb{/}
            \ifx#1\tempsymb
            \barchar@slash
            \barstep@interchar
            \else
            \def\tempsymb{+}
            \ifx#1\tempsymb
            \barchar@plus
            \barstep@interchar
            \else
            \def\tempsymb{\%}
            \ifx#\tempsymb
            \barchar@percent
            \barstep@interchar
            \else
            \def\tempsymb{\$}
            \ifx#1\tempsymb
            \barchar@dollar
            \barstep@interchar
            \else
            % package error
            \fi
            \fi
            \fi
            \fi
            \fi
            \fi
            \fi
            \else
            \tempchar
            \barstep@interchar
            \fi
            \expandafter\barcode@parsechar
            \fi
            }`

            La serie annidata di test condizionali è un po’ poco leggibile ma riguarda solo i simboli mentre con l’idea di \tempchar mi evito un problema maggiore mantenendo l’efficienza di esecuzione.

            Se passo il codice da renderizzare a \barcode con una macro semplice funziona.
            Grazie di nuovo.
            R.

          • #59576
            Up
            0
            Down
            ::

            Ecco come funziona il codice:
            ho creato 43 macro diverse ognuna per i 43 simboli che possono essere rappresentati da code39. Queste macro sono state nominate con \barchar@.
            Per esempio il carattere A è reso dalla macro \barchar@A, quindi quando la macro di parsing passa un singolo carattere costruisco la command sequence relativa per le cifre da 0 a 9 e per le 26 lettere.
            Se tale token non è vuoto (come nella maggioranza dei casi), allora produco il disegno corrispondente delle barre, altrimenti verifico che non sia uno dei simboli speciali, e se non sono in uno di questi casi emetto un messaggio d’errore. Ecco il codice:
            `
            % user interface macro
            \newcommand{\barcode}[1]{%
            \ifx#1\empty
            % package warning
            \else
            \barcode@Start
            \expandafter\uppercase\expandafter{\expandafter\barcode@parsechar#1\@nil}
            \barcode@Stop
            \fi
            }
            %
            \def\barcode@parsechar#1{%
            \ifx#1\@nil\else
            \def\tempsymb{*}
            \ifx#1\tempsymb
            % package error
            \fi
            % command sequence of the char
            \expandafter\let\expandafter\tempchar\csname barchar@#1\endcsname
            \ifx\tempchar\relax
            \ifx#1\space
            \barchar@space
            \barstep@interchar
            \else
            \def\tempsymb{-}
            \ifx#1\tempsymb
            \barchar@bar
            \barstep@interchar
            \else
            \def\tempsymb{.}
            \ifx#1\tempsymb
            \barchar@dot
            \barstep@interchar
            \else
            \def\tempsymb{/}
            \ifx#1\tempsymb
            \barchar@slash
            \barstep@interchar
            \else
            \def\tempsymb{+}
            \ifx#1\tempsymb
            \barchar@plus
            \barstep@interchar
            \else
            \def\tempsymb{\%}
            \ifx#\tempsymb
            \barchar@percent
            \barstep@interchar
            \else
            \def\tempsymb{\$}
            \ifx#1\tempsymb
            \barchar@dollar
            \barstep@interchar
            \else
            % package error
            \fi
            \fi
            \fi
            \fi
            \fi
            \fi
            \fi
            \else
            \tempchar
            \barstep@interchar
            \fi
            \expandafter\barcode@parsechar
            \fi
            }`

            La serie annidata di test condizionali è un po’ poco leggibile ma riguarda solo i simboli mentre con l’idea di \tempchar mi evito un problema maggiore mantenendo l’efficienza di esecuzione.

            Se passo il codice da renderizzare a \barcode con una macro semplice funziona.
            Grazie di nuovo.
            R.

            Non vedo perché tutti quei test, visto che ogni volta che il test ha successo inserisci la macro corrispondente e \barstep@interchar: non basterebbe mettere \barstep@interchar nella definizione di \barcode@dot, per esempio? Ma a quanto capisco quel carattere di separazione ci va sempre, quindi perché fare tanta fatica?

            Ah, puoi benissimo dire
            `\@namedef{barchar@.}{…}`
            ed evitare di guardare se il successivo carattere è il punto. E anche
            `\@namedef{barchar@\detokenize{\$}}{…}`
            e non hai nemmeno bisogno di \tempsymb, purché tu usi
            `\expandafter\let\expandafter\tempchar\csname barchar@\detokenize{#1}\endcsname`
            e a questo punto non ti serve nemmeno \tempchar.

            Vediamo un po’ di snellire quel codice:
            `\newcommand{\barcode@def}[1]{\@namedef{barcode@\detokenize{#1}} % zucchero sintattico
            \barcode@def{A}{…}

            \barcode@def{Z}{…}
            \barcode@def{0}{…}
            \barcode@def{9}{…}
            \barcode@def{ }{…} % space
            \barcode@def{\ }{…} % control space (serve per spazi multipli)
            \barcode@def{-}{…} % period
            \barcode@def{.}{…} % period
            \barcode@def{/}{…} % slash
            \barcode@def{+}{…} % plus
            \barcode@def{\%}{…} % percent
            \barcode@def{$}{…} % dollar
            \barcode@def{\$}{…} % control dollar (non servirebbe)

            \def\barcode@parsechar#1{%
            \ifx#1\@nil\else
            \@ifundefined{barcode@\detokenize{#1}}{\ERROR}{%
            \@nameuse{barcode@\detokenize{#1}}%
            \barstep@interchar}%
            \expandafter\barcode@parsechar
            \fi}`
            Prima di espandere la macro corrispondente al carattere vediamo se è definita; se non lo è emettiamo un messaggio di errore.

            Mi pare un pochino più compatto, non trovi? 🙂

            Si potrebbe anche evitare di dare \% nelle stringhe, di sicuro \$ non serve e va benissimo anche $. Ho messo anche “\ ” perché altrimenti non puoi scrivere due spazi di seguito (a meno di non cambiare il codice di categoria dello spazio durante la lettura dell’argomento). Se definisci anche \barcode@a e così via fino a \barcode@z non hai nemmeno bisogno di \uppercase:
            `\let\barcode@a\barcode@A

            \let\barcode@z\barcode@Z`
            Ciao
            Enrico

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


              Benissimo.
              In realtà avevo pensato di evitare \uppercase con i \let e di provare di inserire i simboli nel nome della macro come per le lettere ed i numeri.

              In fondo il codice non può che essere solamente un inizio di pacchetto.
              I codici a barre sono infatti disegnati con pgf che rispetto a pstricks offre un paio di indiscutibili vantaggi:
              1 – gestione molto più efficiente delle immagini esterne;
              2 – passaggio direttamente al formato pdf.

              Adesso quindi il codice di interfaccia è completo. Quello da proseguire è l’integrazione con il basic layer di PGF e la creazione di oggetti grafici barcode come ad esempio gli oggetti nodo.

              Occorre quindi non solo imparare a costruire gli altri tipi di barcode, come i bidimensionali datamatrix e qrcode, ma sopratutto imparare a programmare PGF.

              Potrebbe venirne fuori l’equivalente del pacchetto pst-barcode per TikZ.
              Grazie.
              Bye

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

          Go to top