2015-09-06 183 views
2

我正在寻找一种脚本,方法或工具来对嵌套的降价列表进行排序。我使用崇高的文本,它有一个内置的排序行功能,但是这个函数破坏了任何嵌套列表的顺序。举例来说,如果我想排序:排序嵌套Markdown列表?

* Zoo Animals 
    * Herbivores 
     * Zebra 
     * Gazelle 
    * Carnivores 
     * Tiger 
     * Lion 
    * Omnivores 
     * Gorilla 
     * Baboon 
     * Chimpanzee 
* Domestic Animals 
    * Canines 
     * German Shepherd 
     * Cocker Spaniel 

用崇高的排序线功能,我得到:

 * Baboon 
     * Chimpanzee 
     * Cocker Spaniel 
     * Gazelle 
     * German Shepherd 
     * Gorilla 
     * Lion 
     * Tiger 
     * Zebra 
    * Canines 
    * Carnivores 
    * Herbivores 
    * Omnivores 
* Domestic Animals 
* Zoo Animals 

显然,这不是我想要的。我要的是一个“之类的作用域”的排序相对于每一颗子弹的水平,而不会破坏嵌套的关系,就像这样:

* Domestic Animals 
    * Canines 
     * Cocker Spaniel 
     * German Shepherd 
* Zoo Animals 
    * Carnivores 
     * Lion 
     * Tiger 
    * Herbivores 
     * Gazelle 
     * Zebra 
    * Omnivores 
     * Baboon 
     * Chimpanzee 
     * Gorilla 

这里的一些事情,我已经研究过我的意念,每个:

  • 使用sublime包进行排序。我找不到一个。但是,也许有一种方法可以使用CSSComb包并将其调整为一个降价列表?
  • 使用sublime中的手动过程对列表进行排序,可能是通过选择项目符号级别并按这些排序进行排序?这样做的问题是要排序的行的选择必须处于相同的缩进级别,并且不能被另一个缩进级别的其他行分隔开,否则排序会完全混乱。除非我错过了什么?
  • 使用脚本对行进行排序。我熟悉ruby,所以也许有办法将这个列表导入到ruby中,并将嵌套列表视为沿着this post的嵌套散列。我确信我可以用ruby脚本来实现我的目标,但是如果已经有了解决方案,我不想走这条路。

你将如何去排序一个大的嵌套降价清单?

更新#1:

@ J4G创建解决了原来的排序问题,看他的答案的链接有很大的Atom包。

上一个列表是一个没有代码块和编号列表的简单列表。然而,排序现实生活中的降价名单的时候,我们有一些代码块和编号列表和线开始有特殊字符 - 嵌套在列表中,像这样:

* Commands 
    * Migrations 
     * `rake db:migrate` - push all migrations to the database 
     * 'STEP=3' - revert the last 3 migrations 
    * `Rails` 
     * `c` - start rails console, run code from your app! 
    * `Rake` 
     * Rake Task 
     ```ruby 
     desc 'process csv' 
     task process_csv: :environment do 
      Node.process_csv 
     end 
     ``` 
* Package Upgrade Status: 
    1. Install Package 
    2. Attach Plugin 
    3. Review Installation 
    ~~~ 
    |Install|Status| 
    |Yes|Pending| 
    ~~~ 

排序后,我会觉得上面的降价名单应该返回因为刻度线和引号没有排序的意义,并且代码块/编号列表已经按照正确的顺序创建。

+1

看起来没有被任何人解决。如果你愿意,我可以非常快速地在Node中写一个。 – Harangue

回答

2

如果你是有兴趣使用Atom(我强烈建议它作为Sublime的免费替代品),我只是做了一个包来做你需要的。

https://atom.io/packages/markdown-sort-list

+1

这似乎是执行所需排序比使用Ruby或其他通用脚本语言更好的方法。 –

3

这是您可以用Ruby做到的一种方法。假设字符串由变量str保存。

代码

def sort_indented(str) 
    arr = str.lines.map { |s| [indentation(s), s.chomp] } 
    indent_offset = arr.map(&:first).uniq.sort.each_with_index. 
    with_object({}) { |(indent, i),h| h[indent] = i } 
    dim_size = indent_offset.size 
    prev = [] 
    arr.map do |indent, s| 
    a = ['']*dim_size 
    offset = indent_offset[indent] 
    a[offset] = s 
    a[0,offset] = prev.first(offset) 
    prev = a 
    a 
    end.sort.map { |a| a[a.rindex { |s| s != '' }] }.join("\n") 
end 

def indentation(s) 
    s[/^\s*/].size 
end 

str =<<THE_END 
* Zoo Animals 
    * Herbivores 
     * Zebra 
     * Gazelle 
    * Carnivores 
     * Tiger 
     * Lion 
    * Omnivores 
     * Gorilla 
     * Baboon 
     * Chimpanzee 
* Domestic Animals 
    * Canines 
     * German Shepherd 
     * Cocker Spaniel 
THE_END 

在Ruby此构造用于定义字符串文字被称为 “here document”,或 “在这里的文档”。

puts sort_indented(str) 

* Domestic Animals 
    * Canines 
     * Cocker Spaniel 
     * German Shepherd 
* Zoo Animals 
    * Carnivores 
     * Lion 
     * Tiger 
    * Herbivores 
     * Gazelle 
     * Zebra 
    * Omnivores 
     * Baboon 
     * Chimpanzee 
     * Gorilla 

一般方法

当红宝石排序数组的数组,如:

a = [1,2,4] 
b = [4,5,6] 
c = [1,2,3,5]] 
[a, b, c] 

它将在前排序每个阵列的第一个元素。由于ac在偏移量零处具有相同的元素1,并且b在该偏移处具有4,所以ac都将在排序后的数组中出现在b之前。 Ruby看着ac的第二个元素打破平局。因为他们都等于2,红宝石进入第三个元素,其中的平局被打破:ca之前,因为3 < 4

我会arr转换成下面的数组:

result =  
[["* Zoo Animals"  , ""    , ""], 
["* Zoo Animals"  , " * Herbivores", ""], 
["* Zoo Animals"  , " * Herbivores", "  * Zebra"], 
["* Zoo Animals"  , " * Herbivores", "  * Gazelle"], 
["* Zoo Animals"  , " * Carnivores", ""], 
["* Zoo Animals"  , " * Carnivores", "  * Tiger"], 
["* Zoo Animals"  , " * Carnivores", "  * Lion"], 
["* Zoo Animals"  , " * Omnivores" , ""], 
["* Zoo Animals"  , " * Omnivores" , "  * Gorilla"], 
["* Zoo Animals"  , " * Omnivores" , "  * Baboon"], 
["* Zoo Animals"  , " * Omnivores" , "  * Chimpanzee"], 
["* Domestic Animals", ""    , ""], 
["* Domestic Animals", " * Canines" , ""], 
["* Domestic Animals", " * Canines" , "  * German Shepherd"], 
["* Domestic Animals", " * Canines" , "  * Cocker Spaniel"]] 

一旦以这种形式,我们可以排序:

result.sort 
    #=> [["* Domestic Animals", "", ""], 
    # ["* Domestic Animals", " * Canines", ""], 
    # ["* Domestic Animals", " * Canines", "  * Cocker Spaniel"], 
    # ["* Domestic Animals", " * Canines", "  * German Shepherd"], 
    # ["* Zoo Animals", "", ""], ["* Zoo Animals", " * Carnivores", ""], 
    # ["* Zoo Animals", " * Carnivores", "  * Lion"], 
    # ["* Zoo Animals", " * Carnivores", "  * Tiger"], 
    # ["* Zoo Animals", " * Herbivores", ""], 
    # ["* Zoo Animals", " * Herbivores", "  * Gazelle"], 
    # ["* Zoo Animals", " * Herbivores", "  * Zebra"], 
    # ["* Zoo Animals", " * Omnivores", ""], 
    # ["* Zoo Animals", " * Omnivores", "  * Baboon"], 
    # ["* Zoo Animals", " * Omnivores", "  * Chimpanzee"], 
    # ["* Zoo Animals", " * Omnivores", "  * Gorilla"]] 

的最后一步是提取从每个最后一个非空字符串排序数组的元素。

详解

首先我们定义一个辅助方法来计算一个字符串的缩进:

def indentation(s) 
    s[/^\s*/].size 
end 

例如,

  #1234 
indentation(" * Herbivores") 
    #=> 4 

现在让字符串转换为线阵列:

a = str.lines 
    #=> ["* Zoo Animals\n", 
    # " * Herbivores\n", 
    # "  * Zebra\n", 
    # "  * Gazelle\n", 
    # " * Carnivores\n", 
    # "  * Tiger\n", 
    # "  * Lion\n", 
    # " * Omnivores\n", 
    # "  * Gorilla\n", 
    # "  * Baboon\n", 
    # "  * Chimpanzee\n", 
    # "* Domestic Animals\n", 
    # " * Canines\n", 
    # "  * German Shepherd\n", 
    # "  * Cocker Spaniel\n"] 

接下来,我们转换a到对一个阵列,所述一对被的a(字符串)的元件的第二元件,与所述换行砍掉结束时,第一个是它的缩进:

arr = a.map { |s| [indentation(s), s.chomp] } 
    # => [[0, "* Zoo Animals"],  [4, " * Herbivores"], 
    #  [8, "  * Zebra"],  [8, "  * Gazelle"], 
    #  [4, " * Carnivores"],  [8, "  * Tiger"], 
    #  [8, "  * Lion"],  [4, " * Omnivores"], 
    #  [8, "  * Gorilla"], [8, "  * Baboon"], 
    #  [8, "  * Chimpanzee"], [0, "* Domestic Animals"], 
    #  [4, " * Canines"],  [8, "  * German Shepherd"], 
    #  [8, "  * Cocker Spaniel"]] 

事实上,我们会一步执行前两个操作:

arr = str.lines.map { |s| [indentation(s), s.chomp] } 

接下来,我们需要知道所使用的缩进:

indents = arr.map { |pair| pair.first } 
    #=> [0, 4, 8, 8, 4, 8, 8, 4, 8, 8, 8, 0, 4, 8, 8] 

,我们可以写更多的经济是这样的:

indents = arr.map(&:first) 

要查找唯一缩进我们写:

unique = indents.uniq 
    #=> [0, 4, 8] 

如果他们不是为了,我们应该对它们进行排序:

sorted = unique.sort 
    #=> [0, 4, 8] 

这三个缩进中的每一个都将对应我们要排序的数组中的偏移量,所以构造一个散列很方便:

indent_offset = sorted.each_with_index.with_object({}) do |(indent, i),h| 
    h[indent] = i 
end 
    #=> {0=>0, 4=>1, 8=>2} 

同样,我们可以通过组合几个步骤执行此计算:

indent_offset = arr.map(&:first).uniq.sort.each_with_index. 
    with_object({}) { |(indent, i),h| h[indent] = i } 

接下来我们取代的arr每个元素与串的3个元素数组:

dim_size = indent_offset.size 
    #=> 3 
prev = [] 
result = arr.map do |indent, s| 
    a = ['']*dim_size 
    offset = indent_offset[indent] 
    a[offset] = s 
    a[0,offset] = prev.first(offset) 
    prev = a 
    a 
end 

结果这个计算是我在上面给出的第一个数组。现在,我们可以排序result获得我下一般方法给了第二阵:

sorted = result.sort 

最后两个步骤来替换最后一个非空字符串sorted每个元素(一个三元素的数组) :

sorted_strings = sorted.map { |a| a[a.rindex { |s| s != '' }] } 

再加入这些字符串成一个字符串:

sorted_strings.join("\n") 
+0

哇,非常彻底的答案!也许这一天可以变成红宝石宝石。 – singularity

+0

谢谢,但我希望已经有一个更好的Ruby gem。当我写这篇文章的时候,我认为Ruby应该是一个更好的方法。 –