
Quiero almacenar varios datos, cada uno del siguiente tipo, para poder manipularlos tanto para formatear como para realizar cálculos. El número de líneas analizadas en el código del usuario no está fijado de antemano.
Ya hice el analizador que extrae estos valores.
LINE: 1
CTXT: xvals
LABEL: t
VAL: 1, 20, 300, 4000
LINE: 2
CTXT: imgs
LABEL: f(t)
VAL: a , b, bb, ccc, dddd
LINE: 3
CTXT: imgs
LABEL: g(t)
VAL: U, V, VV, WWW, XXXX
En esta situación simple, generaré el siguiente resultado (consulte la nicematrix
tabla), pero esta es solo la primera funcionalidad. Me gustaría, por ejemplo, calcular el máximo f
más adelante en el documento. Para hacer eso, necesito recuperar el contexto imgs
para encontrar la etiqueta f(t)
y sus valores asociados.
\documentclass[11pt, a4paper]{article}
\usepackage{nicematrix}
\begin{document}
\section{What the user types}
\begin{verbatim}
\begin{functable}
xvals = t : 1 , 20 , 300 , 4000 ;
imgs = f(t) : a , bb , ccc , dddd ;
g(t) : U , VV , WWW , XXXX
\end{functable}
\end{verbatim}
\section{What the user sees}
$\begin{NiceArray}[cell-space-limits = 3pt]{c*{4}{|c}}
t & 1 & 20 & 300 & 4000
\\ \hline
f(t) & a & bb & ccc & dddd
\\ \hline
g(t) & U & VV & VVV & WWW
\end{NiceArray}$
\section{What can be do after}
The user can ask for example to rebuild the 1st table
with something like this.
\begin{verbatim}
\begin{functable}[rebuild=1]
\end{functable}
\end{verbatim}
The user can also ask to calculate the maximum value
of $f(t)$ via something like \verb+\calcfunctable{max=f(t)}+.
\end{document}
Veo dos posibilidades.
O utilice el
starray
paquete, pero me temo que este proyecto no se mantendrá a largo plazo.O puedo intentar implementar una solución casera que parezca una lista de listas de propiedades.
Se espera una estructura similar a JSON [2024-03-09.v1]
La idea es tener una variable asociada a cada tabla, una variable que se pueda iterar diccionario a diccionario, y por cada diccionario así obtenido tendremos acceso a los diferentes tipos de valores.
[
{
'CTX' : 'xvals',
'VAL' : ['1', '20', '300', '4000'],
'LABEL': 't',
'LINE' : '1'
},
{
'CTX' : 'imgs',
'VAL' : ['a' , 'b', 'bb', 'ccc', 'dddd'],
'LABEL': 'f(t)',
'LINE' : '2'
},
{
'CTX' : 'imgs',
'VAL' : ['U', 'V', 'VV', 'WWW', 'XXXX'],
'LABEL': 'g(t)',
'LINE' : '3'
}
]
Alguna información adicional [2024-01-17.v1]
El analizador proporciona
l3
listas de tokens.El valor de
VAL
las claves se puede utilizar como listas separadas por comas o como secuencias porL3
funciones. La segunda opción debería ser mejor.Los valores se utilizarán en diferentes situaciones, a veces para imprimir una tabla, a veces para realizar cálculos. Esto debería ser similar a lo que se hace enesta respuesta.
Prueba de concepto simplificada [2024-03-09.v1]
\documentclass[12pt]{article}
\ExplSyntaxOn
% -- FUNCTABLE ENV. -- %
\NewDocumentEnvironment{ functable }{ b }{%
\tns_functab_functable:n { #1 }
}{}
\cs_new:Npn \tns_functab_functable:n #1 {
\tns_core_DSL_ctxt_parser:nn { functable } { #1 }
\bigskip\par
NEW ~ DATA ~ \int_use:N \g_tns_functab_id_int
\par
TODO
}
% -- DSL - L3 -- %
\tl_new:N \g_tns_functab_semicolon_tl
\tl_gset:Nn \g_tns_functab_semicolon_tl { ; }
\tl_new:N \g_tns_functab_colon_tl
\tl_gset:Nn \g_tns_functab_colon_tl { : }
\cs_generate_variant:Nn \seq_set_split:Nnn { NV }
\AtBeginDocument {
\tl_gset_rescan:NnV \g_tns_functab_semicolon_tl
{}
\g_tns_functab_semicolon_tl
\tl_gset_rescan:NnV \g_tns_functab_colon_tl
{}
\g_tns_functab_colon_tl
}
% :: AGNOSTIC PARSERS :: %
\int_new:N \g_tns_functab_id_int
\int_gset:Nn \g_tns_functab_id_int { 0 }
\int_new:N \l_tns_core_ctxt_nb_line_int
\seq_new:N \l_tns_core_ctxts_seq
\tl_new:N \l_tns_core_current_ctxt_tl
\cs_new:Npn \tns_core_DSL_ctxt_parser:nn #1#2 {
% The ID nb. of the env.
\int_gincr:N \g_tns_functab_id_int
% Line by line parsing.
%
% Lines are semi-colon separated.
\seq_set_split:NVn \l_tns_core_ctxts_seq
\g_tns_functab_semicolon_tl
{ #2 }
\int_zero:N \l_tns_core_ctxt_nb_line_int
\seq_map_inline:Nn \l_tns_core_ctxts_seq {
\bigskip\par
\int_incr:N \l_tns_core_ctxt_nb_line_int
Line ~ \int_use:N \l_tns_core_ctxt_nb_line_int
\par
% Get the context and its content.
\seq_set_split:Nnn \l_tmpa_seq { = } { ##1 }
\int_set:Nn \l_tmpa_int {\seq_count:N \l_tmpa_seq}
\quad
\int_case:nnF { \int_use:N \l_tmpa_int } {
{ 1 } {
LAST - CTXT: ~
(\tl_use:N \l_tns_core_current_ctxt_tl)
}
{ 2 } {
\seq_pop_left:NN \l_tmpa_seq \l_tns_core_current_ctxt_tl
NEW - CTXT: ~
(\tl_use:N \l_tns_core_current_ctxt_tl)
}
}{
ILLEGAL!
}
% Get the optional label and its content.
\seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl
\seq_set_split:NVV \l_tmpa_seq
\g_tns_functab_colon_tl
\l_tmpa_tl
\int_set:Nn \l_tmpa_int {\seq_count:N \l_tmpa_seq}
\par\quad
\int_case:nnF { \int_use:N \l_tmpa_int } {
{ 1 } {
NO LABEL
}
{ 2 } {
\seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl
LABEL: ~
$(\tl_use:N \l_tmpa_tl)$
}
}{
ILLEGAL!
}
\par\quad
\seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl
VAL: ~
$(\tl_use:N \l_tmpa_tl)$
}
}
\ExplSyntaxOff
\begin{document}
\begin{functable}
xvals = t : 1 , 20 , 300 , 4000 ;
imgs = f(t) : a , bb , ccc , dddd ;
g(t) : U , VV , WWW , XXXX
\end{functable}
\end{document}
Respuesta1
Actualizar
El código se divide en un entorno savefunctable
y un comando \usefunctable
. Ambos toman un nombre como primer argumento. El contenido del entorno savefunctable
se almacena internamente y se puede utilizar más adelante con el comando \usefunctable
especificando el nombre apropiado.
\documentclass[border=6pt,varwidth]{standalone}
\usepackage{nicematrix}
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}
\ExplSyntaxOn
\cs_generate_variant:Nn \seq_map_indexed_inline:Nn { cn }
\cs_generate_variant:Nn \seq_gset_from_clist:Nn { ce }
\seq_new:N \l__projetmbc_functable_seq
\seq_new:N \l__projetmbc_key_name_list_seq
\tl_new:N \l__projetmbc_coordinates_tl
\tl_new:N \l__projetmbc_key_tl
\tl_new:N \l__projetmbc_name_tl
\NewDocumentEnvironment { savefunctable } { m +b }
{
\seq_set_split:Nnn \l__projetmbc_functable_seq { ; } {#2}
\seq_map_inline:Nn \l__projetmbc_functable_seq
{
\seq_set_split:Nnn \l__projetmbc_key_name_list_seq { = } {##1}
\int_compare:nNnT { \seq_count:N \l__projetmbc_key_name_list_seq } = { 2 }
{
\seq_pop_left:NN \l__projetmbc_key_name_list_seq \l__projetmbc_key_tl
\seq_gclear_new:c { g__projetmbc_#1_key_\l__projetmbc_key_tl _seq }
}
\seq_set_split:Nee \l__projetmbc_key_name_list_seq { \c_colon_str } { \seq_item:Nn \l__projetmbc_key_name_list_seq { 1 } }
\seq_pop_left:NN \l__projetmbc_key_name_list_seq \l__projetmbc_name_tl
\seq_gput_right:cV { g__projetmbc_#1_key_\l__projetmbc_key_tl _seq } \l__projetmbc_name_tl
\seq_gclear_new:c { g__projetmbc_#1_key_\l__projetmbc_key_tl _name_\l__projetmbc_name_tl _seq }
\seq_gset_from_clist:ce { g__projetmbc_#1_key_\l__projetmbc_key_tl _name_\l__projetmbc_name_tl _seq } { \seq_item:Nn \l__projetmbc_key_name_list_seq { 1 } }
}
}
{}
\NewDocumentCommand \usefunctable { m m }
{
\str_case:nnF {#2}
{
{ list~of~imgs }
{
\seq_use:cn { g__projetmbc_#1_key_imgs_seq } { , ~ }
}
{ maximum~of~xvals }
{
\fp_eval:n { max ( \seq_use:cn { g__projetmbc_#1_key_xvals_name_\seq_item:cn { g__projetmbc_#1_key_xvals_seq } { 1 }_seq } { , } ) }
}
{ NiceArray }
{
$
\begin { NiceArray }
[ cell-space-limits = 3pt ]
{ c * { \seq_count:c { g__projetmbc_#1_key_xvals_name_\seq_item:cn { g__projetmbc_#1_key_xvals_seq } { 1 }_seq } } { | c } }
\seq_item:cn { g__projetmbc_#1_key_xvals_seq } { 1 } & \seq_use:cn { g__projetmbc_#1_key_xvals_name_\seq_item:cn { g__projetmbc_#1_key_xvals_seq } { 1 }_seq } { & } \\ \hline
\seq_map_indexed_inline:cn { g__projetmbc_#1_key_imgs_seq }
{
##2 & \seq_use:cn { g__projetmbc_#1_key_imgs_name_##2_seq } { & }
\int_compare:nNnF {##1} = { \seq_count:c { g__projetmbc_#1_key_imgs_seq } }
{ \\ \hline }
}
\end { NiceArray }
$
}
{ plot }
{
\tl_build_begin:N \l__projetmbc_coordinates_tl
\seq_map_indexed_inline:cn { g__projetmbc_#1_key_xvals_name_\seq_item:cn { g__projetmbc_#1_key_xvals_seq } { 1 }_seq }
{
\tl_build_put_right:Ne \l__projetmbc_coordinates_tl
{ ( ##2 , \seq_item:cn { g__projetmbc_#1_key_imgs_name_\seq_item:cn { g__projetmbc_#1_key_imgs_seq } { 1 }_seq } {##1} ) }
}
\tl_build_end:N \l__projetmbc_coordinates_tl
\begin { tikzpicture }
\begin { axis }
[
ymin = 0
]
\addplot coordinates
{ \l__projetmbc_coordinates_tl }
;
\end { axis }
\end { tikzpicture }
}
}
{ \errmessage { wrong~option~for~functable~environment } }
}
\ExplSyntaxOff
\begin{document}
\begin{savefunctable}{example 1}
xvals = t : 1 , 20 , 300 , 4000 ;
imgs = f(t) : a , bb , ccc , dddd ;
g(t) : U , VV , WWW , XXXX
\end{savefunctable}
\begin{savefunctable}{example 2}
xvals = t : 1 , 2 , 3 , 4 ;
imgs = f(t) : 8 , 5 , 7 , 6 ;
\end{savefunctable}
Using \texttt{example 1} with \texttt{NiceArray}: \usefunctable{example 1}{NiceArray}
The maximum of the \texttt{xvals} of \texttt{example 2}: \usefunctable{example 2}{maximum of xvals}
The list of \texttt{imgs} of \texttt{example 1}: \usefunctable{example 1}{list of imgs}
A \texttt{plot} for \texttt{example 2}: \usefunctable{example 2}{plot}
\end{document}
Respuesta original
functable
Se define un entorno . Se necesita un argumento obligatorio y luego el cuerpo.
Primero se divide el cuerpo ;
con \seq_set_split:Nnn
. Luego los artículos se dividen =
. Una clave como xvals
o imgs
se almacena en \l__projetmbc_key_tl
.
De manera similar, un nombre como t
o f(t)
se almacena en \l__projetmbc_name_tl
.
El medio ambiente functable
depende del primer argumento obligatorio. A continuación se muestran ejemplos de NiceArray
, maximum of xvals
y .list of imgs
plot
\documentclass[border=6pt,varwidth]{standalone}
\usepackage{nicematrix}
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}
\ExplSyntaxOn
\cs_generate_variant:Nn \seq_map_indexed_inline:Nn { cn }
\cs_generate_variant:Nn \seq_set_from_clist:Nn { ce }
\seq_new:N \l__projetmbc_functable_seq
\seq_new:N \l__projetmbc_key_name_list_seq
\tl_new:N \l__projetmbc_coordinates_tl
\tl_new:N \l__projetmbc_key_tl
\tl_new:N \l__projetmbc_name_tl
\NewDocumentEnvironment { functable } { m +b }
{
\seq_set_split:Nnn \l__projetmbc_functable_seq { ; } {#2}
\seq_map_inline:Nn \l__projetmbc_functable_seq
{
\seq_set_split:Nnn \l__projetmbc_key_name_list_seq { = } {##1}
\int_compare:nNnT { \seq_count:N \l__projetmbc_key_name_list_seq } = { 2 }
{
\seq_pop_left:NN \l__projetmbc_key_name_list_seq \l__projetmbc_key_tl
\seq_clear_new:c { l__projetmbc_key_\l__projetmbc_key_tl _seq }
}
\seq_set_split:Nee \l__projetmbc_key_name_list_seq { \c_colon_str } { \seq_item:Nn \l__projetmbc_key_name_list_seq { 1 } }
\seq_pop_left:NN \l__projetmbc_key_name_list_seq \l__projetmbc_name_tl
\seq_put_right:cV { l__projetmbc_key_\l__projetmbc_key_tl _seq } \l__projetmbc_name_tl
\seq_clear_new:c { l__projetmbc_key_\l__projetmbc_key_tl _name_\l__projetmbc_name_tl _seq }
\seq_set_from_clist:ce { l__projetmbc_key_\l__projetmbc_key_tl _name_\l__projetmbc_name_tl _seq } { \seq_item:Nn \l__projetmbc_key_name_list_seq { 1 } }
}
\str_case:nnF {#1}
{
{ list~of~imgs }
{
\seq_use:Nn \l__projetmbc_key_imgs_seq { , ~ }
}
{ maximum~of~xvals }
{
\fp_eval:n { max ( \seq_use:cn { l__projetmbc_key_xvals_name_\seq_item:Nn \l__projetmbc_key_xvals_seq { 1 }_seq } { , } ) }
}
{ NiceArray }
{
$
\begin { NiceArray }
[ cell-space-limits = 3pt ]
{ c * { \seq_count:c { l__projetmbc_key_xvals_name_\seq_item:Nn \l__projetmbc_key_xvals_seq { 1 }_seq } } { | c } }
\seq_item:Nn \l__projetmbc_key_xvals_seq { 1 } & \seq_use:cn { l__projetmbc_key_xvals_name_\seq_item:Nn \l__projetmbc_key_xvals_seq { 1 }_seq } { & } \\ \hline
\seq_map_indexed_inline:Nn \l__projetmbc_key_imgs_seq
{
##2 & \seq_use:cn { l__projetmbc_key_imgs_name_##2_seq } { & }
\int_compare:nNnF {##1} = { \seq_count:N \l__projetmbc_key_imgs_seq }
{ \\ \hline }
}
\end { NiceArray }
$
}
{ plot }
{
\tl_build_begin:N \l__projetmbc_coordinates_tl
\seq_map_indexed_inline:cn { l__projetmbc_key_xvals_name_\seq_item:Nn \l__projetmbc_key_xvals_seq { 1 }_seq }
{
\tl_build_put_right:Ne \l__projetmbc_coordinates_tl
{ ( ##2 , \seq_item:cn { l__projetmbc_key_imgs_name_\seq_item:Nn \l__projetmbc_key_imgs_seq { 1 }_seq } {##1} ) }
}
\tl_build_end:N \l__projetmbc_coordinates_tl
\begin { tikzpicture }
\begin { axis }
[
ymin = 0
]
\addplot coordinates
{ \l__projetmbc_coordinates_tl }
;
\end { axis }
\end { tikzpicture }
}
}
{ \errmessage { wrong~option~for~functable~environment } }
}
{}
\ExplSyntaxOff
\begin{document}
Using \texttt{NiceArray}:
\begin{functable}{NiceArray}
xvals = t : 1 , 20 , 300 , 4000 ;
imgs = f(t) : a , bb , ccc , dddd ;
g(t) : U , VV , WWW , XXXX
\end{functable}
The maximum of the \texttt{xvals}:
\begin{functable}{maximum of xvals}
xvals = t : 1 , 20 , 300 , 4000 ;
imgs = f(t) : a , bb , ccc , dddd ;
g(t) : U , VV , WWW , XXXX
\end{functable}
The list of \texttt{imgs}:
\begin{functable}{list of imgs}
xvals = t : 1 , 20 , 300 , 4000 ;
imgs = f(t) : a , bb , ccc , dddd ;
g(t) : U , VV , WWW , XXXX
\end{functable}
A plot:
\begin{functable}{plot}
xvals = t : 1 , 2 , 3 , 4 ;
imgs = f(t) : 8 , 5 , 7 , 6 ;
\end{functable}
\end{document}