[编辑:我在此编辑之后的初始解决方案不适用于修改后的问题陈述。但是,我会留下它,因为无论如何它可能会引起人们的兴趣。
据我了解,以下是根据修改后的规则执行排序的方法。如果我误解了规则,我预计修复将是次要的。
使用正则表达式
让我们从我将使用的正则表达式开始:
R = /
\{ # match char
( # begin capture group
\d+ # match one or more digits
(?: # begin non-capture group
\. # match decimal
\d+ # match one or more digits
) # end non-capture group
| # or
\d* # match zero or more digits
) # match end capture group
\} # match char
/x
例子:
a = ["{5}something", "{61}{64}could", "{}be", "{54}{31.24}{0.2}write",
"{11}{21}{87}{65}here", "[]or", "{31}not", "{31} cat"]
a.each_with_object({}) { |s,h| h[s] = s.scan(R).flatten }
# => {"{5}something" =>["5"],
# "{61}{64}could" =>["61", "64"],
# "{}be" =>[""],
# "{54}{31.24}{0.2}write"=>["54", "31.24", "0.2"],
# "{11}{21}{87}{65}here" =>["11", "21", "87", "65"],
# "[]or" =>[],
# "{31}not" =>["31"]
# "{31} cat" =>["31"]}
custom_sort 方法
我们可以将方法custom_sort写成如下(将sort_by改为sort_by!为custom_sort!):
class Array
def custom_sort
sort_by do |s|
a = s.scan(R).flatten
raise SyntaxError,
"'#{s}' contains empty braces" if a.any?(&:empty?)
raise SyntaxError,
"'#{s}' contains zero or > 3 pair of braces" if a.size.zero?||a.size > 3
a.map(&:to_f) << s[a.join.size+2*a.size..-1].tr(' ', 255.chr)
end
end
end
示例
让我们试试吧:
a.custom_sort
#=> SyntaxError: '{}be' contains empty braces
从a 中删除"{}be":
a = ["{5}something", "{61}{64}could", "{54}{31.24}{0.2}write",
"{11}{21}{87}{65}here", "[]or", "{31}not", "{31} cat"]
a.custom_sort
#SyntaxError: '{11}{21}{87}{65}here' contains > 3 pair of braces
删除"{11}{21}{87}{65}here":
a = ["{5}something", "{61}{64}could", "{54}{31.24}{0.2}write",
"[]or", "{31}not", "{31} cat"]
a.custom_sort
#=> SyntaxError: '[]or' contains zero or > 3 pair of braces
删除"[]or":
a = ["{5}something", "{61}{64}could", "{54}{31.24}{0.2}write",
"{31}not", "{31} cat"]
a.custom_sort
#=> ["{5}something",
# "{31}not",
# "{31} cat",
# "{54}{31.24}{0.2}write", "{61}{64}could"]
说明
假设要排序的字符串之一是:
s = "{54}{31.24}{0.2}write a letter"
然后在sort_by 块中,我们将计算:
a = s.scan(R).flatten
#=> ["54", "31.24", "0.2"]
raise SyntaxError, "..." if a.any?(&:empty?)
#=> raise SyntaxError, "..." if false
raise SyntaxError, "..." if a.size.zero?||a.size > 3
#=> SyntaxError, "..." if false || false
b = a.map(&:to_f)
#=> [54.0, 31.24, 0.2]
t = a.join
#=> "5431.240.2"
n = t.size + 2*a.size
#=> 16
u = s[n..-1]
#=> "wr i te"
v = u.tr(' ', 255.chr)
#=> "wr\xFFi\xFFte"
b << v
#=> [54.0, 31.24, 0.2, "wr\xFFi\xFFte"]
请注意,使用String#tr(或者您可以使用String#gsub)会在ASCII 字符排序顺序的末尾放置空格:
255.times.all? { |i| i.chr < 255.chr }
#=> true
潮]
我假设在排序中,字符串对的比较方式类似于Array#<=>。第一个比较考虑每个字符串中第一对大括号内的数字字符串(转换为浮点数之后)。通过比较第二对大括号(转换为浮点数)中的数字字符串来打破平局。如果仍然平局,则比较括在大括号中的第三对数字,依此类推。如果一个字符串具有 n 大括号对,另一个具有 m > n 对,并且大括号内的值与第一个 @ 相同987654347@ 对,我假设第一个字符串在排序中位于第二个字符串之前。
代码
R = /
\{ # match char
(\d+) # capture digits
\} # match char
+ # capture one or more times
/x
class Array
def custom_sort!
sort_by! { |s| s.scan(R).map { |e| e.first.to_f } }
end
end
示例
array = ["{109}{08} OK",
"{109}{07} OK",
"{98} Thx",
"{108}{0.8}{908} aa",
"{108}{0.8}{907} aa",
"{8}{51} lorem ipsum"]
a = array.custom_sort!
#=> ["{8}{51} lorem ipsum",
# "{98} Thx",
# "{108}{0.8}{907} aa",
# "{108}{0.8}{908} aa",
# "{109}{07} OK",
# "{109}{08} OK"]
array == a
#=> true
说明
现在让我们计算Array#sort_by!的块中array的第一个元素的值
s = "{109}{08} OK"
a = s.scan(R)
#=> [["109"], ["08"]]
b = a.map { |e| e.first.to_f }
#=> [109.0, 8.0]
现在让我们对其他字符串做同样的事情并将结果放入一个数组中:
c = array.map { |s| [s, s.scan(R).map { |e| e.first.to_f }] }
#=> [["{8}{51} lorem ipsum", [8.0, 51.0]],
# ["{98} Thx", [98.0]],
# ["{108}{0.8}{907} aa", [108.0, 907.0]],
# ["{108}{0.8}{908} aa", [108.0, 908.0]],
# ["{109}{07} OK", [109.0, 7.0]],
# ["{109}{08} OK", [109.0, 8.0]]]
custom_sort! 中的sort_by 因此等价于:
c.sort_by(&:last).map(&:first)
#=> ["{8}{51} lorem ipsum",
# "{98} Thx",
# "{108}{0.8}{907} aa",
# "{108}{0.8}{908} aa",
# "{109}{07} OK",
# "{109}{08} OK"]