Ich habe einen ersten Satz:
Der schnelle braune Fuchs springt über den faulen Hund.
Ich habe einen neuen Satz (der immer eine Aneinanderreihung des Originalsatzes ist):
Der faule Hund springt über den schnellen braunen Fuchs.
Im Originalsatz möchte ich für jedes Wort die Wortposition entsprechend dem durcheinandergewürfelten Satz hochstellen. Kann mir jemand erklären, wie ich das erreichen kann?
Jeder neuartige Ansatz (mit neuen Paketen) ist willkommen. Vielen Dank im Voraus. Im folgenden MWE erreiche ich offensichtlich nicht das, was ich eigentlich will.
\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}
In diesem Beispiel erhalte ich das gewünschte Ergebnis, wenn ich stattdessen die folgende Definition habe:
\newcommand{\wordsI}
{ 1. The,
7. quick,
8. brown,
9. fox
+
4. jumps,
5. over,
6. the,
2. lazy,
3. dog
}
Ich möchte die Änderung aber nicht manuell vornehmen. Ich suche nach einer Möglichkeit, sie auf der Grundlage des durcheinandergewürfelten Satzes „dynamisch“ zu gestalten.
BEARBEITEN: Dies möchte ich auch in Szenarien wie diesem erreichen:
Anfangssatz:
der schnelle braune Fuchs springt über den faulen Hund.
Durcheinandergewürfelter Satz:
der faule Hund springt über den schnellen braunen Fuchs.
In diesem Fall brauche ich eine Art „Tags“ für die Wörter im Anfangssatz, damit der durcheinandergewürfelte Satz eindeutig ist.
\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
}
Antwort1
Meiner Meinung nach ist das Interessanteste an TeX der Schriftsatz und das Schlimmste die Programmiermöglichkeit. Daher ist es am besten, solche Programmierungen außerhalb von TeX durchzuführen (so weit weg wie möglich!) und TeX ausschließlich für den Schriftsatz zu verwenden. Alles kannmöglichmit TeX, aber es ist nicht unbedingt die einfachste/wartungsfreundlichste Lösung.
Wenn Sie TeX verwenden, ist diese Art der Programmierung mit LuaTeX jedoch einfacher (zumindest für mich und ich denke, für die meisten Leute). Kompilieren Sie die folgende Datei mit lualatex
(Ihre „Tags“ sind optional: Sie können jedes Wort wie markieren the(1) quick(2) ...
oder nur die doppelten Wörter markieren):
\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}
wobei jumble.lua
(was in dieselbe .tex
Datei integriert werden könnte, ich es aber lieber getrennt behalte) das Folgende ist:
-- 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
Dadurch entsteht
wie in der Frage.
Beachten Sie, dass Sie dies durch Verschieben etwas kürzer machen können (siehe z. B. die erste Überarbeitung dieser Antwort), aber ich finde es am saubersten, die Satzanweisungen .tex
und die Programmierung (so weit wie möglich) in der .lua
Datei zu belassen.
Antwort2
Etwas wie das?
\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}