我有一句开篇语:
敏捷的棕色狐狸跳过了懒狗。
我有一个新的句子(它总是与原始句子混杂在一起):
懒狗跳过敏捷的棕色狐狸。
在原句中,对于每个单词,我想根据乱序的句子标出单词位置。有人能指导我如何实现这一点吗?
任何新颖的方法(使用新包)都值得赞赏。提前致谢。在接下来的 MWE 中,我显然没有实现我真正想要的。
\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}
在这个例子中,如果我有以下定义,我将得到我需要的结果:
\newcommand{\wordsI}
{ 1. The,
7. quick,
8. brown,
9. fox
+
4. jumps,
5. over,
6. the,
2. lazy,
3. dog
}
但是,我不想手动进行更改。我正在寻找一种基于混乱的句子使其“动态”的方法。
编辑: 即使在这样的场景中我也想实现这一点:
首句:
敏捷的棕色狐狸跳过了懒狗。
句子混乱:
懒狗跳过敏捷的棕色狐狸。
在这种情况下,我需要为初始句子中的单词添加某种“标签”,以使混乱的句子不产生歧义。
\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
}
答案1
在我看来,TeX 最有趣的地方在于它的排版,最糟糕的地方在于它的编程功能,因此最好在 TeX 之外进行此类编程(尽可能远离!),并且仅将 TeX 用于排版。一切都可能可能的使用 TeX,但它不一定是最简单/最易于维护的解决方案。
不过,如果使用 TeX,这种编程用 LuaTeX 更容易完成(至少对我来说是这样,我想大多数人也是如此)。使用编译以下文件lualatex
(我让你的“标签”是可选的:你可以像 一样标记每个单词the(1) quick(2) ...
,或者只标记重复的单词):
\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}
其中jumble.lua
(可以内联到同一个.tex
文件中,但我更喜欢保持分开)如下:
-- 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
这产生了
正如问题中所说。
请注意,您可以通过移动内容使其更短一些(例如,参见此答案的第一次修订),但我发现最干净的做法是(尽可能)保留文件中的排版说明.tex
和文件中的编程.lua
。
答案2
像这样吗?
\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}