Eu tenho uma frase inicial:
A rápida raposa marrom salta sobre o cachorro preguiçoso.
Tenho uma nova frase (que é sempre uma confusão da frase original):
O cachorro preguiçoso salta sobre a rápida raposa marrom.
Na frase original, para cada palavra, quero sobrescrever a posição da palavra de acordo com a frase confusa. Alguém pode me orientar sobre como posso conseguir isso?
Qualquer abordagem nova (usando novos pacotes) é apreciada. Desde já, obrigado. No seguinte MWE, obviamente não estou conseguindo o que realmente quero.
\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}
Neste exemplo, obterei o resultado necessário se, em vez disso, tiver a seguinte definição:
\newcommand{\wordsI}
{ 1. The,
7. quick,
8. brown,
9. fox
+
4. jumps,
5. over,
6. the,
2. lazy,
3. dog
}
Mas não quero fazer a alteração manualmente. Estou procurando uma maneira de torná-lo 'dinâmico' com base na frase confusa.
EDITAR: Quero conseguir isso mesmo em cenários como este:
Frase inicial:
a rápida raposa marrom salta sobre o cachorro preguiçoso.
Frase confusa:
o cachorro preguiçoso salta sobre a rápida raposa marrom.
Nesse caso, preciso ter algum tipo de 'etiqueta' para as palavras da frase inicial para que a frase confusa não seja ambígua.
\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
}
Responder1
Na IMO, a coisa mais interessante sobre o TeX é sua composição tipográfica e o pior é sua facilidade de programação, então é melhor fazer essa programação fora do TeX (o mais longe possível!) e usar o TeX apenas para composição tipográfica. Tudo pode serpossívelcom TeX, mas não será necessariamente a solução mais fácil/de maior manutenção.
Ainda assim, se estiver usando TeX, esse tipo de programação é mais fácil de fazer com LuaTeX (pelo menos para mim, e imagino que para a maioria das pessoas). Compile o seguinte arquivo com lualatex
(deixei suas “tags” serem opcionais: você pode marcar cada palavra como the(1) quick(2) ...
, ou marcar apenas as palavras 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}
onde jumble.lua
(que pode estar embutido no mesmo .tex
arquivo, mas prefiro manter separado) é o seguinte:
-- 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
Isso produz
como na pergunta.
Observe que você pode tornar isso um pouco mais curto (por exemplo, veja a primeira revisão desta resposta) movendo as coisas, mas acho mais limpo manter (tanto quanto possível) as instruções de composição no .tex
arquivo e a programação no .lua
arquivo .
Responder2
Algo assim?
\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}