从电子表格生成字母索引

从电子表格生成字母索引

我有一个物理课讲座主题的文本文件,如下所示:

1/14,Galilean relativity,Einsteinian relativity,Minkowski space,Henri Poincare,,
1/16,Lorentz transformations,Velocity transformations,Proper time,Light aberration,Lorentz tensors formalism,Minkowski space
1/23,Lorentz boost,Lorentz group,Poincare group,contravariant tensor,covariant tensor,d'Alembertian

我实际上将其存储为 Google Doc,因此我可以将其导出为 tsv、ods、xslx 等,而不是 csv。

我想生成一个像书后面那样的索引,按日期字母顺序列出主题,例如

d'Albertian 1/23
... (more entries)
Minkowski space 1/14 1/16
... (more entries)
Velocity transformations 1/16

或者如果你想要更花哨一点:

d'Albertian ................. 1/23
... (more entries)
Minkowski space ............. 1/14, 1/16
... (more entries)
Velocity transformations .... 1/16

我首先想到的是使用LaTeX,但索引包似乎都是按页码而不是日期之类的任意字符串进行索引。事实上,“MakeIndex 假设所有页码都是阿拉伯数字或小写罗马数字;”http://www.tex.ac.uk/ctan/indexing/makeindex/doc/makeindex.pdf。此外,的输入文件makeindex必须是一个每行一个主题和页码的列表;它只进行排序和格式化:http://www.troubleshooters.com/linux/lyx/makeindex.htm

因此,我要找的软件需要执行以下操作:

  1. 接受 csv、tsv 或其他电子表格格式。这将是理想的,但我也可以接受可以相当容易地从电子表格文件生成的文本格式,例如通过替换awksed
  2. 将每行的第一个条目(例如日期1/14)与以下每个条目(例如主题Galilean relavityMinkowski space等等)关联。
  3. 按字母顺序对所有日期的所有主题进行排序。
  4. 将多次出现的主题合并为一个条目,列出该主题出现的每个日期。
  5. 以标准格式输出结果。

我对该软件的唯一要求是它能在 Linux 上运行。

我对输出格式并不挑剔;文本文件、LaTeX、HTML、odf 等都可以,只要我能打印出纸质副本即可。

答案1

您反对 mono 吗?如果不反对,那么就使用 F# 交互吧

http://fsharp.org/use/linux/

并使用以下 F# 脚本(您也可以编译它)

open System
open System.IO

let inputFile = "inputFile.csv"
let outputFile = "out.txt"

File.ReadAllLines(inputFile)
|> Seq.filter (fun i -> i.Length > 0)
|> Seq.collect
    (fun i ->
        let fields = i.Split(',')
        let date = fields.[0]
        fields.[1..] |> Array.map (fun entry -> date,entry)
    )
|> Seq.groupBy snd
|> Seq.sortBy (fun (entry,_) -> entry.ToUpper())
|> Seq.filter (fun (entry,_) -> entry <> "")
|> Seq.map 
    (fun (entry,dates) ->
        let dates = dates |> Seq.map fst |> Seq.sort
        let datestr = String.Join (", ",dates)
        String.Format("{0} ........ {1}", entry, datestr)
    )
|> (fun i -> File.WriteAllLines(outputFile,i))

这将生成一个文本文件:

contravariant tensor ........ 1/23
covariant tensor ........ 1/23
d'Alembertian ........ 1/23
Einsteinian relativity ........ 1/14
Galilean relativity ........ 1/14
Henri Poincare ........ 1/14
Light aberration ........ 1/16
Lorentz boost ........ 1/23
Lorentz group ........ 1/23
Lorentz tensors formalism ........ 1/16
Lorentz transformations ........ 1/16
Minkowski space ........ 1/14, 1/16
Poincare group ........ 1/23
Proper time ........ 1/16
Velocity transformations ........ 1/16

虽然不是你想要的,但修改上述代码以生成 latex 标记会很容易。只需修改以下行

String.Format("{0} ........ {1}", entry, datestr)

为每行添加所需的标记。不幸的是,我现在无法访问 mono,因此使用 .NET 进行测试。

答案2

Shell 脚本和出色的awk命令:

awk -F, '
  { for (i=2;i<=NF;i++) { subject_dates[$i]=subject_dates[$i] " " $1 } }
  END { for (idx in subject_dates) { print idx, subject_dates[idx] } }
'

答案3

F#和解决方案都awk经过一些调整后效果很好。不过,我决定使用以下 Python 脚本:

#!/usr/bin/env python
import csv, sys
mydict = {}
for line in open(sys.argv[1],'r'):
    tokens = line.strip().split(',')
    item, keys = tokens[0], tokens[1:]
    for key in keys:
        if key != '':
            # If the key is already in the dictionary,
            # just add it to the set, otherwise make an
            # empty set to add the item to.
            mydict.setdefault(key, set()).add(item)
for key in sorted(mydict.keys(), key=str.lower):
    print key + ' \dotfill ' + ', '.join(mydict[key])

在这种情况下,item对应于日期,keys对应于主题。\dotfill是用点填充水平空间的 LaTeX 标记。

相关内容