Tengo una frase inicial:
El rápido zorro marrón salta sobre el perro perezoso..
Tengo una oración nueva (que siempre es una mezcla de la oración original):
El perro perezoso salta sobre el veloz zorro marrón..
En la oración original, para cada palabra, quiero superponer la posición de la palabra según la oración mezclada. ¿Alguien puede guiarme sobre cómo puedo lograr esto?
Se agradece cualquier enfoque novedoso (utilizando nuevos paquetes). Gracias de antemano. En el siguiente MWE, obviamente no logro lo que realmente quiero.
\documentclass[12pt]{memoir}
\usepackage{listofitems}
\usepackage{amsmath}
\newcommand{\wordsI}
{ 1. The,
2. quick,
3. brown,
4. fox
+
5. jumps,
6. over,
7. the,
8. lazy,
9. dog
}
\newcommand{\wordsII}
{ The
lazy
dog
jumps
over
the
quick
brown
fox
}
% Tokenize the words in order to display them
\newcommand{\tokenize}[1]
{%
\setsepchar{+/,/./}
\readlist*\textarray{#1}
\foreachitem\groupoflines\in\textarray
{
\setsepchar{,}
\readlist*\linearray{\groupoflines}
\foreachitem\line\in\linearray
{
\setsepchar{.}
\readlist*\wordarray{\line}
$ \text{\wordarray[2]} ^ {\wordarray[1]} $
}%
\newline
}
}
\begin{document}
\noindent
Actual sentence:
\newline
% The splitting of the sentence in 2 lines is intentional
\tokenize{\wordsI}
\noindent
Jumbled sentence:
\textbf{\wordsII}
\end{document}
En este ejemplo, obtendré el resultado que necesito si tengo la siguiente definición:
\newcommand{\wordsI}
{ 1. The,
7. quick,
8. brown,
9. fox
+
4. jumps,
5. over,
6. the,
2. lazy,
3. dog
}
Pero no quiero realizar el cambio manualmente. Estoy buscando una manera de hacerlo "dinámico" basándose en la oración confusa.
EDITAR: Quiero lograr esto incluso en escenarios como este:
Frase inicial:
El veloz zorro marrón salta sobre el perro perezoso..
Frase confusa:
el perro perezoso salta sobre el veloz zorro marrón.
En este caso, necesito tener algún tipo de "etiquetas" para las palabras de la oración inicial para que la oración confusa no sea ambigua.
\newcommand{\wordsI}
{ 1. the,
2. quick,
3. brown,
4. fox
+
5. jumps,
6. over,
7. the,
8. lazy,
9. dog
}
\newcommand{\wordsII}
{ 7. the
8. lazy
9. dog
5. jumps
6. over
1. the
2. quick
3. brown
4. fox
}
Respuesta1
En mi opinión, lo más interesante de TeX es su composición tipográfica y lo peor es su facilidad de programación, por lo que es mejor realizar dicha programación fuera de TeX (¡lo más lejos posible!) y usar TeX únicamente para la composición tipográfica. todo puede serposiblecon TeX, pero no será necesariamente la solución más fácil ni más fácil de mantener.
Aún así, si usas TeX, este tipo de programación es más fácil de hacer con LuaTeX (al menos para mí, e imagino que para la mayoría de las personas). Compile el siguiente archivo con lualatex
(he dejado que sus "etiquetas" sean opcionales: puede etiquetar cada palabra como the(1) quick(2) ...
o etiquetar solo las palabras duplicadas):
\documentclass[12pt]{memoir}
\usepackage{amsmath} % For \text
\newcommand{\printword}[2]{$\text{#1} ^ {#2}$\quad} % Or whatever formatting you like.
\newcommand{\linesep}{\newline}
\directlua{dofile('jumble.lua')}
\newcommand{\printjumble}[2]{
\directlua{get_sentence1_lines()}{#1}
\directlua{get_sentence2_words()}{#2}
%
\noindent
Actual sentence:
\newline
\directlua{print_sentence1_lines()}
\noindent
Jumbled sentence:
\textbf{\directlua{print_sentence2()}}
}
\begin{document}
\printjumble{
the(1) quick brown fox
+
jumps over the(7) lazy dog
}{
the(7) lazy dog jumps over the(1) quick brown fox
}
\end{document}
donde jumble.lua
(que podría estar incluido en el mismo .tex
archivo, pero prefiero mantenerlo separado) es el siguiente:
-- Expected from TeX: before calling print_sentence1_lines(),
-- call get_sentence1_lines() and get_sentence2_words()
-- define \printword and \linesep.
-- Globals: sentence2_words, position_for_word, sentence1_lines
function get_sentence1_lines()
sentence1_lines = token.scan_string()
end
function get_sentence2_words()
local sentence2 = token.scan_string()
sentence2_words = {}
position_for_word = {}
local i = 0
for word in string.gmatch(sentence2, "%S+") do
i = i + 1
assert(position_for_word[word] == nil, string.format('Duplicate word: %s', word))
sentence2_words[i] = without_tags(word)
position_for_word[word] = i
end
end
function print_sentence2()
for i, word in ipairs(sentence2_words) do
tex.print(word)
end
end
function print_sentence1_lines()
for line in string.gmatch(sentence1_lines, "[^+]+") do
for word in string.gmatch(line, "%S+") do
position = position_for_word[word]
assert(position_for_word[word] ~= nil, string.format('New word: %s', word))
tex.print(string.format([[\printword{%s}{%s}]], without_tags(word), position))
end
tex.print([[\linesep]])
end
end
function without_tags(word)
local new_word = string.gsub(word, "%(.*%)", "")
return new_word
end
Esto produce
como en la pregunta.
Tenga en cuenta que puede hacer esto un poco más corto (por ejemplo, vea la primera revisión de esta respuesta) moviendo las cosas, pero me parece más limpio mantener (tanto como sea posible) las instrucciones de composición tipográfica en el .tex
archivo y la programación en el .lua
archivo. .
Respuesta2
¿Algo como esto?
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \l_jsp_sentence_temp_seq
\seq_new:N \l_jsp_sentence_original_seq
\seq_new:N \l_jsp_sentence_jumbled_seq
\prop_new:N \l_jsp_sentence_original_ind_prop
\prop_new:N \l_jsp_sentence_jumbled_ind_prop
\int_new:N \l_jsp_sentence_word_int
\NewDocumentCommand{\parseoriginalsentence}{m}
{
\seq_set_split:Nnn \l_jsp_sentence_temp_seq { + } { #1 }
\seq_clear:N \l_jsp_sentence_original_seq
\prop_clear:N \l_jsp_sentence_original_ind_prop
\seq_map_inline:Nn \l_jsp_sentence_temp_seq
{
\int_zero:N \l_jsp_sentence_word_int
\clist_map_inline:nn { ##1 }
{
\int_incr:N \l_jsp_sentence_word_int
\seq_put_right:Nn \l_jsp_sentence_original_seq { ####1 }
\prop_put:Nnx \l_jsp_sentence_original_ind_prop
{ ####1 } { \int_to_arabic:n { \l_jsp_sentence_word_int } }
}
\seq_put_right:Nn \l_jsp_sentence_original_seq { + }
}
}
\NewDocumentCommand{\parsejumbledsentence}{m}
{
\prop_clear:N \l_jsp_sentence_jumbled_ind_prop
\seq_set_split:Nnn \l_jsp_sentence_jumbled_seq { , } { #1 }
\int_zero:N \l_jsp_sentence_word_int
\seq_map_inline:Nn \l_jsp_sentence_jumbled_seq
{
\int_incr:N \l_jsp_sentence_word_int
\prop_put:Nnx \l_jsp_sentence_jumbled_ind_prop
{ ##1 } { \int_to_arabic:n { \l_jsp_sentence_word_int } }
}
}
\NewDocumentCommand{\printoriginalsentence}{s}
{
\IfBooleanTF{#1}
{
\jsp_sentence_print_from_original:
}
{
\jsp_sentence_print_from_jumbled:
}
}
\cs_new_protected:Nn \jsp_sentence_print_from_original:
{
\seq_map_inline:Nn \l_jsp_sentence_original_seq
{
\tl_if_eq:nnTF { ##1 } { + }
{
\par
}
{
\prop_item:Nn \l_jsp_sentence_original_ind_prop { ##1 }.\nobreakspace ##1 ~
}
}
}
\cs_new_protected:Nn \jsp_sentence_print_from_jumbled:
{
\seq_map_inline:Nn \l_jsp_sentence_original_seq
{
\tl_if_eq:nnTF { ##1 } { + }
{
\par
}
{
\prop_item:Nn \l_jsp_sentence_jumbled_ind_prop { ##1 }.\nobreakspace ##1 ~
}
}
}
\ExplSyntaxOff
\begin{document}
\parseoriginalsentence{
The,
quick,
brown,
fox
+
jumps,
over,
the,
lazy,
dog
}
\parsejumbledsentence{
The,
lazy,
dog,
jumps,
over,
the,
quick,
brown,
fox
}
\printoriginalsentence*
\bigskip
\printoriginalsentence
\end{document}