class Net::IMAP::SequenceSet
IMAP 序列集是一组消息序列号或唯一标识符(“UID”)。它包含数字和数字范围。这些数字都是非零的无符号 32 位整数和一个特殊值("*"
),表示邮箱中的最大值。
某些类型的 IMAP 响应将包含一个 SequenceSet
,例如 "MODIFIED"
ResponseCode
的数据。某些 IMAP 命令可能会接收一个 SequenceSet
作为参数,例如 IMAP#search
、IMAP#fetch
和 IMAP#store
。
创建序列集¶ ↑
不带任何参数的 SequenceSet.new
创建一个空的序列集。请注意,空的序列集在 IMAP 语法中是无效的。
set = Net::IMAP::SequenceSet.new set.empty? #=> true set.valid? #=> false set.valid_string #!> raises DataFormatError set << 1..10 set.empty? #=> false set.valid? #=> true set.valid_string #=> "1:10"
SequenceSet.new
可以接收一个可选的参数:一个非零的 32 位无符号整数、一个范围、一个 sequence-set
格式的字符串、另一个序列集、一个 Set(仅包含数字或 *
)或一个包含其中任何一个的数组(数组输入可以嵌套)。
set = Net::IMAP::SequenceSet.new(1) set.valid_string #=> "1" set = Net::IMAP::SequenceSet.new(1..100) set.valid_string #=> "1:100" set = Net::IMAP::SequenceSet.new(1...100) set.valid_string #=> "1:99" set = Net::IMAP::SequenceSet.new([1, 2, 5..]) set.valid_string #=> "1:2,5:*" set = Net::IMAP::SequenceSet.new("1,2,3:7,5,6:10,2048,1024") set.valid_string #=> "1,2,3:7,5,6:10,2048,1024" set = Net::IMAP::SequenceSet.new(1, 2, 3..7, 5, 6..10, 2048, 1024) set.valid_string #=> "1:10,55,1024:2048"
使用带有一个或多个参数的 ::[]
创建一个冻结的 SequenceSet
。使用 ::[]
无法创建无效的(空)集合。
set = Net::IMAP::SequenceSet["1,2,3:7,5,6:10,2048,1024"] set.valid_string #=> "1,2,3:7,5,6:10,2048,1024" set = Net::IMAP::SequenceSet[1, 2, [3..7, 5], 6..10, 2048, 1024] set.valid_string #=> "1:10,55,1024:2048"
规范化形式¶ ↑
当使用单个 String 值创建序列集时,将保留该 string
表示形式。SequenceSet 的内部表示形式会隐式地对所有条目进行排序、删除重复的数字并合并相邻或重叠的范围。大多数枚举方法和基于偏移量的方法都使用这种规范化表示形式。大多数修改方法会将 string
转换为其规范化形式。
在某些情况下,字符串表示形式的顺序很重要,例如 ESORT
、CONTEXT=SORT
和 UIDPLUS
扩展。使用 entries
或 each_entry
按其原始顺序枚举集合。要在修改集合时保留 string
顺序,请使用 append
、string=
或 replace
。
使用 *
¶ ↑
IMAP 序列集可以包含一个特殊值 "*"
,它表示正在使用的最大数字。来自 RFC9051 §9 中的 seq-number
在消息序列号的情况下,它是非空邮箱中消息的数量。在唯一标识符的情况下,它是邮箱中最后一条消息的唯一标识符;如果邮箱为空,则为邮箱当前的 UIDNEXT 值。
创建 SequenceSet
时,*
可以作为 -1
、"*"
、:*
、无限范围或以 -1
结尾的范围输入。当转换为 elements
、ranges
或 numbers
时,它将输出为 :*
或无限范围。例如
Net::IMAP::SequenceSet["1,3,*"].to_a #=> [1, 3, :*] Net::IMAP::SequenceSet["1,234:*"].to_a #=> [1, 234..] Net::IMAP::SequenceSet[1234..-1].to_a #=> [1234..] Net::IMAP::SequenceSet[1234..].to_a #=> [1234..] Net::IMAP::SequenceSet[1234..].to_s #=> "1234:*" Net::IMAP::SequenceSet[1234..-1].to_s #=> "1234:*"
使用 limit
将 "*"
转换为最大值。当范围包含 "*"
时,始终会匹配最大值
Net::IMAP::SequenceSet["9999:*"].limit(max: 25) #=> Net::IMAP::SequenceSet["25"]
令人惊讶的 *
行为¶ ↑
当集合包含 *
时,某些方法可能会有令人惊讶的行为。
例如,complement
将 *
视为其自身的数字。这样,集合及其 complement
的 intersection
将始终为空。这与 IMAP 服务器解释集合的方式不同:它会将 *
转换为邮箱中的消息数或 UIDNEXT
,具体取决于情况。并且在将 limit
应用于每个集合后,集合及其补集之间将存在重叠
~Net::IMAP::SequenceSet["*"] == Net::IMAP::SequenceSet[1..(2**32-1)] ~Net::IMAP::SequenceSet[1..5] == Net::IMAP::SequenceSet["6:*"] set = Net::IMAP::SequenceSet[1..5] (set & ~set).empty? => true (set.limit(max: 4) & (~set).limit(max: 4)).to_a => [4]
在计算集合中的数字数量时,除了当集合中也存在 UINT32_MAX
时,会计算 *
UINT32_MAX = 2**32 - 1 Net::IMAP::SequenceSet["*"].count => 1 Net::IMAP::SequenceSet[1..UINT32_MAX - 1, :*].count => UINT32_MAX Net::IMAP::SequenceSet["1:*"].count => UINT32_MAX Net::IMAP::SequenceSet[UINT32_MAX, :*].count => 1 Net::IMAP::SequenceSet[UINT32_MAX..].count => 1
这里有什么?¶ ↑
SequenceSet
提供以下方法:
创建 SequenceSet 的方法¶ ↑
-
::[]
:从一个或多个输入创建经过验证的冻结序列集。 -
::new
:创建一个新的可变序列集,该序列集可能为空(无效)。 -
::try_convert
:对对象调用to_sequence_set
并验证结果是否为SequenceSet
。 -
::empty
:返回冻结的空(无效)SequenceSet
。 -
::full
:返回包含每个可能数字的冻结SequenceSet
。
用于比较的方法¶ ↑
与另一个 SequenceSet 进行比较
与可转换为 SequenceSet 的对象进行比较
-
===
:返回给定对象是否完全包含在self
中;如果该对象无法转换为兼容类型,则返回nil
。 -
intersect?
(别名为overlap?
):返回self
和给定对象是否具有任何公共元素。 -
disjoint?
:返回self
和给定对象是否没有公共元素。
用于查询的方法¶ ↑
这些方法不会修改 self
。
集合成员资格
-
include_star?
:返回集合是否包含*
。
最小值和最大值元素
按偏移量访问值
-
at
:返回给定偏移量处的数字。 -
find_index
:返回给定数字在集合中的偏移量
集合基数
用于迭代的方法¶ ↑
-
each_element
:生成集合中排序和合并的每个数字和范围,并返回self
。 -
each_entry
:生成集合中未排序且不删除重复数字或合并范围的每个数字和范围,并返回self
。 -
entries
:返回集合中每个未排序且不删除重复数字或合并范围的数字和范围的数组。 -
each_range
:将集合中的每个元素作为 Range 生成并返回self
。 -
ranges
:返回集合中每个元素的数组,将数字转换为单个值的范围。 -
each_number
:生成集合中的每个数字并返回self
。 -
numbers
: 返回一个数组,其中包含集合中的每个数字,并将范围扩展为所有包含的数字。
集合运算方法¶ ↑
这些方法不会修改 self
。
-
#&(别名为
intersection
):返回一个新的集合,其中包含self
和另一个对象共有的所有成员。 -
-
(别名为difference
):返回self
的一个副本,其中删除了另一个对象中的所有成员。 -
#^(别名为
xor
):返回一个新的集合,其中包含self
和另一个对象的所有成员,但排除两者共有的成员。 -
#~(别名为
complement
):返回一个新集合,其中包含所有不在self
中的成员 -
limit
: 返回self
的一个副本,其中将*
替换为给定的最大值,并删除所有超出该最大值的成员。
赋值方法¶ ↑
这些方法在 self
中添加或替换元素。
-
add?
:如果给定对象不是集合中的元素,则将其添加并返回self
;否则,返回nil
。 -
merge
:将多个元素合并到集合中;返回self
。 -
append
:将给定对象添加到集合中,将其附加到现有字符串中,并返回self
。 -
replace
:使用给定对象的内容替换集合的内容。 -
complement!
: 使用其自身的complement
替换集合的内容。
删除方法¶ ↑
这些方法从 self
中删除元素。
-
clear
:删除集合中的所有元素;返回self
。 -
delete
:从集合中删除给定对象;返回self
。 -
delete?
:如果给定对象是集合中的元素,则将其删除并返回;否则,返回nil
。 -
delete_at
:删除给定偏移量处的数字。 -
slice!
:删除给定偏移量或偏移量范围处的数字或连续数字。 -
subtract
:从集合中删除每个给定对象;返回self
。 -
limit!
: 将*
替换为给定的最大值,并删除所有超出该最大值的成员;返回self
。
IMAP 字符串格式化方法¶ ↑
-
to_s
: 返回sequence-set
字符串,当集合为空时,返回空字符串。 -
string
: 返回sequence-set
字符串,当集合为空时,返回 nil。 -
valid_string
: 返回sequence-set
字符串,当集合为空时,引发DataFormatError
。 -
normalized_string
: 返回一个sequence-set
字符串,其元素已排序和合并,当集合为空时,返回 nil。 -
normalize
: 返回一个新集合,其中包含此集合的规范化sequence-set
表示形式。 -
normalize!
: 将string
更新为其规范化的sequence-set
表示形式,并返回self
。
常量
- EMPTY
有意在类实现之后定义
- FULL
- STARS
“*”的有效输入
- STAR_INT
在内部表示“*”,以简化排序(等)
- UINT32_MAX
最大的可能的非零无符号 32 位整数
公共类方法
返回一个冻结的 SequenceSet
,由 values
构建。
一个空的 SequenceSet
是无效的,将引发一个 DataFormatError
。
使用 ::new
创建一个可变或空的 SequenceSet
。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 297 def [](first, *rest) if rest.empty? if first.is_a?(SequenceSet) && first.frozen? && first.valid? first else new(first).validate.freeze end else new(first).merge(*rest).validate.freeze end end
返回一个冻结的空集合单例。请注意,有效的 IMAP 序列集不能为空,因此该集合是无效的。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 328 def empty; EMPTY end
返回一个冻结的完整集合单例: "1:*"
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 331 def full; FULL end
从 input
创建一个新的 SequenceSet
对象,它可以是另一个 SequenceSet
、一个 IMAP
格式化的 sequence-set
字符串、一个数字、一个范围、:*
或这些的可枚举对象。
使用 ::[]
创建一个冻结的(非空)SequenceSet
。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 340 def initialize(input = nil) input ? replace(input) : clear end
如果 obj
是一个 SequenceSet
,则返回 obj
。如果 obj
响应 to_sequence_set
,则调用 obj.to_sequence_set
并返回结果。否则返回 nil
。
如果 obj.to_sequence_set
没有返回 SequenceSet
,则会引发异常。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 318 def try_convert(obj) return obj if obj.is_a?(SequenceSet) return nil unless obj.respond_to?(:to_sequence_set) obj = obj.to_sequence_set return obj if obj.is_a?(SequenceSet) raise DataFormatError, "invalid object returned from to_sequence_set" end
公共实例方法
返回一个新的序列集,其中仅包含此集合和 other
共有的数字。
other
可以是任何会被 ::new
接受的对象:非零 32 位无符号整数、范围、sequence-set
格式的字符串、另一个序列集或包含这些的可枚举对象。
Net::IMAP::SequenceSet[1..5] & [2, 4, 6] #=> Net::IMAP::SequenceSet["2,4"]
(seqset & other)
等效于 (seqset - ~other)
。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 619 def &(other) remain_frozen dup.subtract SequenceSet.new(other).complement! end
返回通过复制此集合并删除 other
中出现的每个数字而构建的新序列集。
other
可以是任何会被 ::new
接受的对象:非零 32 位无符号整数、范围、sequence-set
格式的字符串、另一个序列集或包含这些的可枚举对象。
Net::IMAP::SequenceSet[1..5] - 2 - 4 - 6 #=> Net::IMAP::SequenceSet["1,3,5"]
相关:subtract
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 601 def -(other) remain_frozen dup.subtract other end
当另一个 SequenceSet
表示相同的消息标识符时,返回 true。编码差异(如顺序、重叠或重复)将被忽略。
Net::IMAP::SequenceSet["1:3"] == Net::IMAP::SequenceSet["1:3"] #=> true Net::IMAP::SequenceSet["1,2,3"] == Net::IMAP::SequenceSet["1:3"] #=> true Net::IMAP::SequenceSet["1,3"] == Net::IMAP::SequenceSet["3,1"] #=> true Net::IMAP::SequenceSet["9,1:*"] == Net::IMAP::SequenceSet["1:*"] #=> true
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 437 def ==(other) self.class == other.class && (to_s == other.to_s || tuples == other.tuples) end
返回 other
是否包含在集合中。如果在将 other
转换为可比较类型时引发 StandardError,则返回 nil
。
相关:cover?
,include?
,include_star?
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 467 def ===(other) cover?(other) rescue nil end
从 self
返回一个数字或一个子集,而不修改该集合。
当给定整数参数 index
时,返回偏移量 index
处的数字
set = Net::IMAP::SequenceSet["10:15,20:23,26"] set[0] #=> 10 set[5] #=> 15 set[10] #=> 26
如果 index
为负数,则相对于 self
的末尾计数
set = Net::IMAP::SequenceSet["10:15,20:23,26"] set[-1] #=> 26 set[-3] #=> 22 set[-6] #=> 15
如果 index
超出范围,则返回 nil
。
set = Net::IMAP::SequenceSet["10:15,20:23,26"] set[11] #=> nil set[-12] #=> nil
结果基于规范化的集合(已排序且已删除重复项),而不是 string
的分配值。
set = Net::IMAP::SequenceSet["12,20:23,11:16,21"] set[0] #=> 11 set[-1] #=> 23
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1085 def [](index, length = nil) if length then slice_length(index, length) elsif index.is_a?(Range) then slice_range(index) else at(index) end end
返回一个新的序列集,其中包含此集合和 other
之间的唯一数字。
other
可以是任何会被 ::new
接受的对象:非零 32 位无符号整数、范围、sequence-set
格式的字符串、另一个序列集或包含这些的可枚举对象。
Net::IMAP::SequenceSet[1..5] ^ [2, 4, 6] #=> Net::IMAP::SequenceSet["1,3,5:6"]
(seqset ^ other)
等效于 ((seqset | other) - (seqset & other))
。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 640 def ^(other) remain_frozen (self | other).subtract(self & other) end
将一个范围或数字添加到集合并返回 self
。
string
将被重新生成。使用 merge
一次添加多个元素。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 670 def add(object) tuple_add input_to_tuple object normalize! end
将一个范围或数字添加到集合并返回 self
。
与 add
, merge
或 union
不同,新值将附加到 string
。这可能会导致 string
出现重复或顺序错误。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 680 def append(object) modifying! tuple = input_to_tuple object entry = tuple_to_str tuple tuple_add tuple @string = -(string ? "#{@string},#{entry}" : entry) self end
从 self
返回一个数字,而不修改集合。行为与 []
相同,只是 at
只允许一个整数参数。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1034 def at(index) index = Integer(index.to_int) if index.negative? reverse_each_tuple_with_index do |min, max, idx_min, idx_max| idx_min <= index and return from_tuple_int(min + (index - idx_min)) end else each_tuple_with_index do |min, _, idx_min, idx_max| index <= idx_max and return from_tuple_int(min + (index - idx_min)) end end nil end
删除所有元素并返回 self。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 343 def clear; @tuples, @string = [], nil; self end
将 SequenceSet
转换为其自身的 complement
。它将包含所有可能的值,除了当前在集合中的值。
相关:complement
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1165 def complement! return replace(self.class.full) if empty? return clear if full? flat = @tuples.flat_map { [_1 - 1, _2 + 1] } if flat.first < 1 then flat.shift else flat.unshift 1 end if STAR_INT < flat.last then flat.pop else flat.push STAR_INT end @tuples = flat.each_slice(2).to_a normalize! end
返回集合中 numbers
的计数。
如果集合中同时存在 *
和 2**32 - 1
(最大 32 位无符号整数值),它们将只被计数一次。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 986 def count @tuples.sum(@tuples.count) { _2 - _1 } + (include_star? && include?(UINT32_MAX) ? -1 : 0) end
返回 other
是否包含在该集合中。other
可以是任何能被 ::new
接受的对象。
相关:===
, include?
, include_star?
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 479 def cover?(other) input_to_tuples(other).none? { !include_tuple?(_1) } end
当有效时返回一个包含 normalized_string
的数组,否则返回一个空数组。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 386 def deconstruct; valid? ? [normalized_string] : [] end
从集合中删除指定的值,并返回删除的值。如果未删除任何内容,则返回 nil
。
当删除指定的 number
参数时,返回一个整数。
set = Net::IMAP::SequenceSet.new [5..10, 20] set.delete?(7) #=> 7 set #=> #<Net::IMAP::SequenceSet "5:6,8:10,20"> set.delete?("20") #=> 20 set #=> #<Net::IMAP::SequenceSet "5:6,8:10"> set.delete?(30) #=> nil
当指定并删除 *
或 -1
时,返回 :*
。
set = Net::IMAP::SequenceSet.new "5:9,20,35,*" set.delete?(-1) #=> :* set #=> #<Net::IMAP::SequenceSet "5:9,20,35">
当指定范围时,返回一个新的 SequenceSet
。
set = Net::IMAP::SequenceSet.new [5..10, 20] set.delete?(9..) #=> #<Net::IMAP::SequenceSet "9:10,20"> set #=> #<Net::IMAP::SequenceSet "5:8"> set.delete?(21..) #=> nil
删除后,string
将被重新生成。
相关:delete
, delete_at
, subtract
, difference
, disjoint?
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 746 def delete?(object) tuple = input_to_tuple object if tuple.first == tuple.last return unless include_tuple? tuple tuple_subtract tuple normalize! from_tuple_int tuple.first else copy = dup tuple_subtract tuple normalize! copy if copy.subtract(self).valid? end end
如果集合和给定对象没有公共元素,则返回 true
,否则返回 false
。
Net::IMAP::SequenceSet["5:10"].disjoint? "7,9,11" #=> false Net::IMAP::SequenceSet["5:10"].disjoint? "11:33" #=> true
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 531 def disjoint?(other) empty? || input_to_tuples(other).none? { intersect_tuple? _1 } end
将 elements
中的每个数字或范围(或 :*
)传递给代码块,并返回 self。当不带代码块调用时,返回一个枚举器。
返回的数字是排序和去重的,即使输入 string
不是。参见 normalize
。
相关:elements
, each_entry
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 921 def each_element # :yields: integer or range or :* return to_enum(__method__) unless block_given? @tuples.each do yield tuple_to_entry _1 end self end
将 string
中的每个数字或范围传递给代码块,并返回 self
。当不带代码块调用时,返回一个枚举器。
条目按照它们在 string
中出现的相同顺序产生,没有排序、去重或合并。当 string
处于其规范化形式时,这将产生与 each_element
相同的值。
相关:entries
, each_element
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 907 def each_entry(&block) # :yields: integer or range or :* return to_enum(__method__) unless block_given? return each_element(&block) unless @string @string.split(",").each do yield tuple_to_entry str_to_tuple _1 end self end
将 numbers
中的每个数字传递给代码块,并返回 self。如果集合包含 *
,将引发 RangeError。
当不带代码块调用时,返回一个枚举器(即使集合包含 *
)。
相关:numbers
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 961 def each_number(&block) # :yields: integer return to_enum(__method__) unless block_given? raise RangeError, '%s contains "*"' % [self.class] if include_star? each_element do |elem| case elem when Range then elem.each(&block) when Integer then block.(elem) end end self end
将 ranges
中的每个范围传递给代码块,并返回 self。当不带代码块调用时,返回一个枚举器。
相关:ranges
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 943 def each_range # :yields: range return to_enum(__method__) unless block_given? @tuples.each do |min, max| if min == STAR_INT then yield :*.. elsif max == STAR_INT then yield min.. else yield min..max end end self end
返回一个范围、整数和 :*
的数组。
返回的元素是排序和合并的,即使输入 string
不是。*
将最后排序。参见 normalize
。
单独来说,*
转换为 :*
。包含 *
的范围转换为无限范围。使用 limit
可以将这两种情况都转换为最大值。
如果原始输入是无序的或包含重叠的范围,则返回的范围将被排序和合并。
Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].elements #=> [2, 5..9, 11..12, :*]
相关:each_element
, ranges
, numbers
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 848 def elements; each_element.to_a end
如果集合不包含任何元素,则返回 true。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 561 def empty?; @tuples.empty? end
哈希相等性需要相同的编码 string
表示形式。
Net::IMAP::SequenceSet["1:3"] .eql? Net::IMAP::SequenceSet["1:3"] #=> true Net::IMAP::SequenceSet["1,2,3"].eql? Net::IMAP::SequenceSet["1:3"] #=> false Net::IMAP::SequenceSet["1,3"] .eql? Net::IMAP::SequenceSet["3,1"] #=> false Net::IMAP::SequenceSet["9,1:*"].eql? Net::IMAP::SequenceSet["1:*"] #=> false
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 456 def eql?(other) self.class == other.class && string == other.string end
返回 number
在集合中的索引,如果 number
不在集合中,则返回 nil
。
相关:[]
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 997 def find_index(number) number = to_tuple_int number each_tuple_with_index do |min, max, idx_min| number < min and return nil number <= max and return from_tuple_int(idx_min + (number - min)) end nil end
冻结并返回集合。冻结的 SequenceSet
是 Ractor 安全的。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 414 def freeze return self if frozen? string @tuples.each(&:freeze).freeze super end
如果集合包含每个可能的元素,则返回 true。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 564 def full?; @tuples == [[1, STAR_INT]] end
参见 eql?
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 459 def hash; [self.class, string].hash end
当给定数字或范围在 self
中时,返回 true
,否则返回 false
。除非 number
是整数、范围或 *
,否则返回 false
。
set = Net::IMAP::SequenceSet["5:10,100,111:115"] set.include? 1 #=> false set.include? 5..10 #=> true set.include? 11..20 #=> false set.include? 100 #=> true set.include? 6 #=> true, covered by "5:10" set.include? 4..9 #=> true, covered by "5:10" set.include? "4:9" #=> true, strings are parsed set.include? 4..9 #=> false, intersection is not sufficient set.include? "*" #=> false, use #limit to re-interpret "*" set.include? -1 #=> false, -1 is interpreted as "*" set = Net::IMAP::SequenceSet["5:10,100,111:*"] set.include? :* #=> true set.include? "*" #=> true set.include? -1 #=> true set.include? 200.. #=> true set.include? 100.. #=> false
相关:include_star?
, cover?
, ===
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 505 def include?(element) include_tuple? input_to_tuple element end
当集合包含 *
时,返回 true
。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 510 def include_star?; @tuples.last&.last == STAR_INT end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1211 def inspect if empty? (frozen? ? "%s.empty" : "#<%s empty>") % [self.class] elsif frozen? "%s[%p]" % [self.class, to_s] else "#<%s %p>" % [self.class, to_s] end end
如果集合和给定对象有任何公共元素,则返回 true
,否则返回 false
。
Net::IMAP::SequenceSet["5:10"].intersect? "7,9,11" #=> true Net::IMAP::SequenceSet["5:10"].intersect? "11:33" #=> false
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 519 def intersect?(other) valid? && input_to_tuples(other).any? { intersect_tuple? _1 } end
返回一个冻结的 SequenceSet
,其中 *
转换为 max
,删除了大于 max
的数字和范围,并且将包含 max
的范围转换为以 max
结束。
Net::IMAP::SequenceSet["5,10:22,50"].limit(max: 20).to_s #=> "5,10:20"
*
始终被解释为最大值。当集合包含 *
时,它将被设置为等于该限制。
Net::IMAP::SequenceSet["*"].limit(max: 37) #=> Net::IMAP::SequenceSet["37"] Net::IMAP::SequenceSet["5:*"].limit(max: 37) #=> Net::IMAP::SequenceSet["5:37"] Net::IMAP::SequenceSet["500:*"].limit(max: 37) #=> Net::IMAP::SequenceSet["37"]
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1138 def limit(max:) max = to_tuple_int(max) if empty? then self.class.empty elsif !include_star? && max < min then self.class.empty elsif max(star: STAR_INT) <= max then frozen? ? self : dup.freeze else dup.limit!(max: max).freeze end end
删除所有大于 max
的成员,并返回 self。如果 *
是一个成员,它将被转换为 max
。
相关:limit
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1151 def limit!(max:) star = include_star? max = to_tuple_int(max) tuple_subtract [max + 1, STAR_INT] tuple_add [max, max ] if star normalize! end
返回 self
中的最大值,当集合包含 *
时返回 star
,当集合为空时返回 nil
。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 539 def max(star: :*) (val = @tuples.last&.last) && val == STAR_INT ? star : val end
返回 self
中的最小值,当集合中唯一的值是 *
时返回 star
,当集合为空时返回 nil
。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 547 def min(star: :*) (val = @tuples.first&.first) && val == STAR_INT ? star : val end
返回一个包含 self
中最小值和最大值的 2 元素数组,当集合为空时返回 nil
。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 555 def minmax(star: :*); [min(star: star), max(star: star)] unless empty? end
返回一个新的 SequenceSet
,其中包含标准化的字符串表示形式。
返回的集合的 string
是排序和去重的。相邻或重叠的元素将被合并为一个更大的范围。
Net::IMAP::SequenceSet["1:5,3:7,10:9,10:11"].normalize #=> Net::IMAP::SequenceSet["1:7,9:11"]
相关方法: normalize!
, normalized_string
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1184 def normalize str = normalized_string return self if frozen? && str == string remain_frozen dup.instance_exec { @string = str&.-@; self } end
重置 string
为排序、去重和合并后的形式。返回 self
。
相关方法: normalize
, normalized_string
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1194 def normalize! @string = nil self end
返回标准化的 sequence-set
字符串表示形式,排序并去重。相邻或重叠的元素将被合并为一个更大的范围。当集合为空时返回 nil
。
Net::IMAP::SequenceSet["1:5,3:7,10:9,10:11"].normalized_string #=> "1:7,9:11"
相关方法: normalize!
, normalize
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1207 def normalized_string @tuples.empty? ? nil : -@tuples.map { tuple_to_str _1 }.join(",") end
返回序列集中所有数字值的排序数组。
返回的数字是排序和去重的,即使输入 string
不是。参见 normalize
。
Net::IMAP::SequenceSet["2,5:9,6,12:11"].numbers #=> [2, 5, 6, 7, 8, 9, 11, 12]
如果集合包含 *
,则会引发 RangeError。请参阅 limit
。
Net::IMAP::SequenceSet["10000:*"].numbers #!> RangeError
警告:即使排除包含 *
的集合,也可能很容易创建巨大的结果。可能会返回一个包含超过 40 亿个整数的数组,在 64 位架构上需要高达 32GiB 的内存。
Net::IMAP::SequenceSet[10000..2**32-1].numbers # ...probably freezes the process for a while... #!> NoMemoryError (probably)
为了安全起见,请考虑使用 limit
或 intersection
来设置上限。或者,使用 each_element
,each_range
,甚至 each_number
来避免分配结果数组。
相关方法: elements
, ranges
, to_set
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 897 def numbers; each_number.to_a end
返回范围数组
返回的元素是排序和合并的,即使输入 string
不是。*
将最后排序。参见 normalize
。
*
转换为无限范围。单独使用时,*
转换为 :*..
。使用 limit
将 *
设置为最大值。
返回的范围将被排序和合并,即使输入 string
没有被排序和合并。*
将排在最后。请参阅 normalize
。
Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].ranges #=> [2..2, 5..9, 11..12, :*..] Net::IMAP::SequenceSet["123,999:*,456:789"].ranges #=> [123..123, 456..789, 999..]
相关方法: each_range
, elements
, numbers
, to_set
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 869 def ranges; each_range.to_a end
用 other
的内容替换集合的内容,并返回 self
。
other
可以是另一个 SequenceSet
,也可以是 IMAP
sequence-set
字符串、数字、范围、*
或这些内容的可枚举对象。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 350 def replace(other) case other when SequenceSet then initialize_dup(other) when String then self.string = other else clear; merge other end self end
从集合中删除由给定 index
、start
和 length
或偏移量 range
指示的数字或连续数字。返回删除的数字或序列集,如果未删除任何内容,则返回 nil
。参数的解释方式与 slice
或 []
相同。
删除后,string
将被重新生成。
相关方法: slice
, delete_at
, delete
, delete?
, subtract
, difference
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 786 def slice!(index, length = nil) deleted = slice(index, length) and subtract deleted deleted end
返回 IMAP sequence-set
字符串表示形式,当集合为空时返回 nil
。请注意,空集合在 IMAP 语法中是无效的。
当集合为空时,使用 valid_string
引发异常,或使用 to_s
返回空字符串。
如果集合是从单个字符串创建的,则不会标准化。如果更新集合,则字符串将标准化。
相关方法: valid_string
, normalized_string
, to_s
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 382 def string; @string ||= normalized_string if valid? end
为 string
分配一个新字符串,并重置 elements
以匹配。它不能设置为空字符串,请分配 nil
或使用 clear
代替。该字符串已验证但未标准化。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 395 def string=(str) if str.nil? clear else str = String.try_convert(str) or raise ArgumentError, "not a string" tuples = str_to_tuples str @tuples, @string = [], -str tuples_add tuples end end
从集合中删除任何给定的 objects
中出现的所有元素,并返回 self
。
objects
可以是任何被 ::new
接受的对象:非零 32 位无符号整数、范围、sequence-set
格式的字符串、其他序列集或包含任何这些内容的可枚举对象。
相关方法: difference
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 816 def subtract(*objects) tuples_subtract input_to_tuples objects normalize! end
返回 IMAP sequence-set
字符串表示形式,当集合为空时返回空字符串。请注意,空集合在 IMAP 语法中是无效的。
相关方法: valid_string
, normalized_string
, to_s
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 411 def to_s; string || "" end
当集合为空时返回 false。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 558 def valid?; !empty? end
返回 IMAP sequence-set
字符串表示形式,当集合为空时引发 DataFormatError
。
使用 string
返回 nil
或使用 to_s
返回空字符串而不会出错。
相关方法: string
, normalized_string
, to_s
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 366 def valid_string raise DataFormatError, "empty sequence-set" if empty? string end
返回一个新的序列集,其中添加了 other
对象中的每个数字。
other
可以是任何会被 ::new
接受的对象:非零 32 位无符号整数、范围、sequence-set
格式的字符串、另一个序列集或包含这些的可枚举对象。
Net::IMAP::SequenceSet["1:5"] | 2 | [4..6, 99] #=> Net::IMAP::SequenceSet["1:6,99"]
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 582 def |(other) remain_frozen dup.merge other end
返回 self 的补集,即一个 SequenceSet
,它包含除了此集合中那些之外的所有数字。
~Net::IMAP::SequenceSet.full #=> Net::IMAP::SequenceSet.empty ~Net::IMAP::SequenceSet.empty #=> Net::IMAP::SequenceSet.full ~Net::IMAP::SequenceSet["1:5,100:222"] #=> Net::IMAP::SequenceSet["6:99,223:*"] ~Net::IMAP::SequenceSet["6:99,223:*"] #=> Net::IMAP::SequenceSet["1:5,100:222"]
相关方法: complement!
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 658 def ~; remain_frozen dup.complement! end
私有实例方法
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1008 def each_tuple_with_index idx_min = 0 @tuples.each do |min, max| yield min, max, idx_min, (idx_max = idx_min + (max - min)) idx_min = idx_max + 1 end idx_min end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1301 def from_tuple_int(num) num == STAR_INT ? :* : num end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1310 def include_tuple?((min, max)) range_gte_to(min)&.cover?(min..max) end
冻结的克隆是浅拷贝的
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1244 def initialize_clone(other) other.frozen? ? super : initialize_dup(other) end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1248 def initialize_dup(other) @tuples = other.tuples.map(&:dup) @string = other.string&.-@ super end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1254 def input_to_tuple(obj) obj = input_try_convert obj case obj when *STARS, Integer then [int = to_tuple_int(obj), int] when Range then range_to_tuple(obj) when String then str_to_tuple(obj) else raise DataFormatError, "expected number or range, got %p" % [obj] end end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1265 def input_to_tuples(obj) obj = input_try_convert obj case obj when *STARS, Integer, Range then [input_to_tuple(obj)] when String then str_to_tuples obj when SequenceSet then obj.tuples when Set then obj.map { [to_tuple_int(_1)] * 2 } when Array then obj.flat_map { input_to_tuples _1 } when nil then [] else raise DataFormatError, "expected nz-number, range, string, or enumerable; " \ "got %p" % [obj] end end
与 SequenceSet#try_convert 不同,此方法返回 Integer、Range、String、Set、Array 或…任何类型的对象。
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1283 def input_try_convert(input) SequenceSet.try_convert(input) || Integer.try_convert(input) || String.try_convert(input) || input end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1312 def intersect_tuple?((min, max)) range = range_gte_to(min) and range.include?(min) || range.include?(max) || (min..max).cover?(range) end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1317 def modifying! if frozen? raise FrozenError, "can't modify frozen #{self.class}: %p" % [self] end end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1414 def nz_number(num) String === num && !/\A[1-9]\d*\z/.match?(num) and raise DataFormatError, "%p is not a valid nz-number" % [num] NumValidator.ensure_nz_number Integer num rescue TypeError # To catch errors from Integer() raise DataFormatError, $!.message end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1409 def range_gte_to(num) first, last = tuples.bsearch { _2 >= num } first..last if first end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1290 def range_to_tuple(range) first = to_tuple_int(range.begin || 1) last = to_tuple_int(range.end || :*) last -= 1 if range.exclude_end? && range.end && last != STAR_INT unless first <= last raise DataFormatError, "invalid range for sequence-set: %p" % [range] end [first, last] end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1241 def remain_frozen(set) frozen? ? set.freeze : set end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1017 def reverse_each_tuple_with_index idx_max = -1 @tuples.reverse_each do |min, max| yield min, max, (idx_min = idx_max - (max - min)), idx_max idx_max = idx_min - 1 end idx_max end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1096 def slice_length(start, length) start = Integer(start.to_int) length = Integer(length.to_int) raise ArgumentError, "length must be positive" unless length.positive? last = start + length - 1 unless start.negative? && start.abs <= length slice_range(start..last) end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1104 def slice_range(range) first = range.begin || 0 last = range.end || -1 last -= 1 if range.exclude_end? && range.end && last != STAR_INT if (first * last).positive? && last < first SequenceSet.empty elsif (min = at(first)) max = at(last) if max == :* then self & (min..) elsif min <= max then self & (min..max) else SequenceSet.empty end end end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1305 def str_to_tuple(str) raise DataFormatError, "invalid sequence set string" if str.empty? str.split(":", 2).map! { to_tuple_int _1 }.minmax end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1304 def str_to_tuples(str) str.split(",", -1).map! { str_to_tuple _1 } end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1300 def to_tuple_int(obj) STARS.include?(obj) ? STAR_INT : nz_number(obj) end
–|=====| |=====新元组=====| 追加 ?????????-|=====新元组=====|-|===较低===|– 插入
|=====new tuple=====|
———??=======较低=======??————— 无操作
———??===较低==|–|==| 连接剩余 ———??===较低==|–|==|—-|===较高===|– 连接直到较高 ———??===较低==|–|==|–|=====较高===|– 连接到较高
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1336 def tuple_add(tuple) modifying! min, max = tuple lower, lower_idx = tuple_gte_with_index(min - 1) if lower.nil? then tuples << tuple elsif (max + 1) < lower.first then tuples.insert(lower_idx, tuple) else tuple_coalesce(lower, lower_idx, min, max) end end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1346 def tuple_coalesce(lower, lower_idx, min, max) return if lower.first <= min && max <= lower.last lower[0] = [min, lower.first].min lower[1] = [max, lower.last].max lower_idx += 1 return if lower_idx == tuples.count tmax_adj = lower.last + 1 upper, upper_idx = tuple_gte_with_index(tmax_adj) if upper tmax_adj < upper.first ? (upper_idx -= 1) : (lower[1] = upper.last) end tuples.slice!(lower_idx..upper_idx) end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1405 def tuple_gte_with_index(num) idx = tuples.bsearch_index { _2 >= num } and [tuples[idx], idx] end
|====tuple================|
–|====| 不再有 1. 无操作 –|====|—————————|====较低====|– 2. 无操作 ——-|======较低================|—————- 3. 分割 ——–|=====较低================|—————- 4. 修剪开头
——-|======较低====????????????—————– 修剪较低 ——–|=====较低====????????????—————– 删除较低
——-??=====较低===============|—————– 5. 修剪/删除一个 ——-??=====较低====|–|====| 不再有 6. 删除其余 ——-??=====较低====|–|====|—|====较高====|– 7. 删除直到 ——-??=====较低====|–|====|–|=====较高====|– 8. 删除并修剪
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1373 def tuple_subtract(tuple) modifying! min, max = tuple lower, idx = tuple_gte_with_index(min) if lower.nil? then nil # case 1. elsif max < lower.first then nil # case 2. elsif max < lower.last then tuple_trim_or_split lower, idx, min, max else tuples_trim_or_delete lower, idx, min, max end end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 929 def tuple_to_entry((min, max)) if min == STAR_INT then :* elsif max == STAR_INT then min.. elsif min == max then min else min..max end end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1303 def tuple_to_str(tuple) tuple.uniq.map{ from_tuple_int _1 }.join(":") end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1384 def tuple_trim_or_split(lower, idx, tmin, tmax) if lower.first < tmin # split tuples.insert(idx, [lower.first, tmin - 1]) end lower[0] = tmax + 1 end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1323 def tuples_add(tuples) tuples.each do tuple_add _1 end; self end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1324 def tuples_subtract(tuples) tuples.each do tuple_subtract _1 end; self end
# File net-imap-0.5.4/lib/net/imap/sequence_set.rb, line 1391 def tuples_trim_or_delete(lower, lower_idx, tmin, tmax) if lower.first < tmin # trim lower lower[1] = tmin - 1 lower_idx += 1 end if tmax == lower.last # case 5 upper_idx = lower_idx elsif (upper, upper_idx = tuple_gte_with_index(tmax + 1)) upper_idx -= 1 # cases 7 and 8 upper[0] = tmax + 1 if upper.first <= tmax # case 8 (else case 7) end tuples.slice!(lower_idx..upper_idx) end