整成一个 gem 了 ...
gem ins regexp_optimized_union
require 'regexp_optimized_union'
Regexp.optimized_union %w[foobar foobaz foobarbaz]
整了一个 Regexp.list
(其实我的编辑器里也需要类似的功能), 希望没奇怪的 bug 哈
class Regexp
class TrieNode < Hash
attr_accessor :parent, :op_maybe, :op_suffix
def []= k, v
super(k, v)
v.parent = self
end
def single_branch?
empty? or (size == 1 and !op_maybe and values[0].single_branch?)
end
def single_char?
size == 1 and values[0].empty?
end
# prereq: single_branch?
def to_chars
if empty?
[]
else
[keys[0], *values[0].to_chars]
end
end
# returns: regexp source for common suffix
def compute_common_suffix
branches = map do |key, value|
[key, *value.to_chars]
end
branches.each &:reverse!
max_common_size = branches.map(&:size).min
common_size = nil
max_common_size.downto 1 do |i|
found = true
branches.map {|b| b.take i }.each_cons(2) do |b1, b2|
if b1 != b2
found = false
break
end
end
if found
common_size = i
break
end
end
if common_size
common = branches[0].take(common_size).reverse.join
if branches.all?{|b| b.size == common_size + 1 }
diff = branches.map(&:last).join
"[#{diff}]#{common}"
else
diff = branches.map do |b|
b.drop(common_size).reverse.join
end.join '|'
"(?:#{diff})#{common}"
end
end
end
def to_re_src
return '' if empty?
res = compute_common_suffix if op_suffix
if !res
can_be_branched = true
res = map do |key, value|
"#{key}#{value.to_re_src}"
end.join '|'
end
if op_maybe
if single_char?
"#{res}?"
else
"(?:#{res})?"
end
else
if can_be_branched and size > 1 and parent
"(?:#{res})"
else
res
end
end
end
end
def self.list a
trie = TrieNode.new
term_nodes = {}
# build trie
a.each do |s|
next if s.empty?
t = trie
s.chars.each do |c|
c = Regexp.escape c
unless t[c]
t[c] = TrieNode.new
end
t = t[c]
end
term_nodes[t] = true
t.op_maybe = true
end
# tag op_suffix nodes
term_nodes.each do |node, _|
next unless node.empty?
while node = node.parent and !node.op_suffix and !node.op_maybe
if node.size > 1
if node.values.all?(&:single_branch?)
node.op_suffix = true
end
break
end
end
end
Regexp.new trie.to_re_src
end
end
if __FILE__ == $PROGRAM_NAME
{
[] => //,
['foo'] => /foo/,
['foo', 'bar'] => /foo|bar/,
['foo', 'foob', 'bar'] => /foob?|bar/,
['foo', 'foobar'] => /foo(?:bar)?/,
['bazfoo', 'bazfoobar', 'bazbar'] => /baz(?:foo(?:bar)?|bar)/,
['fooabar', 'foobbar'] => /foo[ab]bar/,
['fooabar', 'foobazbar'] => /foo(?:a|baz)bar/,
['foobar', 'fooabar', 'foogabar'] => /foo(?:|a|ga)bar/
}.each do |a, r|
l = Regexp.list a
a.each do |s|
raise "#{l.inspect} from #{a.inspect} not match #{s.inspect}" if l.match(s).offset(0) != [0, s.size]
end
raise "expected #{r} from #{a.inspect} but got #{l}" if r != l
end
puts 'test success!'
end
doc.gsub(/(?<=\b\w)\w{2,}(?=\w\b)/) {|s| s.chars.to_a.shuffle.join }
p.s. 需要 Ruby 2.0 Onigmo
好吧看了编译出来的 Onig 字节码,应该没做这种优化
PATTERN: /fooa|foob|fooc/ (US-ASCII)
optimize: EXACT_BM
anchor: []
sub anchor: []
exact: [foo]: length: 3
code length: 36
0:[push:(10)] 5:[exact4:fooa] 10:[jump:(20)] 15:[push:(10)] 20:[exact4:foob]
25:[jump:(5)] 30:[exact4:fooc] 35:[end]
然后测了下做不做优化的区别
require 'benchmark'
os = 'o'*10000
r1 = /f#{os}a|f#{os}b|f#{os}c/
r2 = /f#{os}[abc]/
s = "f#{os}c"
puts Benchmark.measure{ 1000.times{r1.match s} }
puts Benchmark.measure{ 1000.times{r2.match s} }
10000 个子的话,做这种优化会快一倍多点的样子,但是短的就不清楚了
可以一做...
做了有用么?貌似正则引擎已经做了提取公共子表达式的优化了?
elsif 和 perl 一样,没必要发明个新的...
Ruby 1.9 的主要 IO 函数已经是不需要进程内同步了,爬虫或 http 服务器已经可以用多线程提高速度了。
什么时候能请 koichi 来一次就好了
html5 的话是用音频或者视频的 video_or_audio.currentTime = x
跳转到第 x 秒的
但是字幕和时间数据如何对应是个问题,如果一个 video 已经有字幕文件,可以解析字幕文件把时间轴弄出来,否则就要用类似卡拉 OK 的制作工具来录入时间轴了。
@hlxwell 做过 web 版时间轴的录入工具哦。做法就是把音频慢放 (这也是有一个工具可以转换的), 一个人每听一句话就按一下空格键把时间对上,一般还要设一个反映延迟来修正录入后的时间数据。
thePlant 的 @sunfmin 做过,每个词还能链接到词典解释的...
终于阿!
@huacnlee 是的,我就用了一个 fuzzy_file_finder 的 gem, 还有 yaml, http 什么的处理都容易多了
代码第一需要正确,其次就是追求那个优雅了...
优雅没有统一的标准,以衣服做类比的话,我觉得"少"可以称优雅... 以信息论测量的话,我觉得如果两段代码作用一样,熵低的可以称优雅:写起来不费劲,读起来也轻松,改起来也无鸭梨。
而我刚好有一段估算熵的脚本 ---- entropy.rb 哦!!! (你需要准备一个小词典,这个词典应包含一些常用词和一段 matz 写的 Ruby 代码)
#! /usr/bin/env ruby
require 'zlib'
DICT = DATA.read
def zlen(s)
z = Zlib::Deflate.new
out = z.deflate(DICT + s, Zlib::FINISH)
z.close
out.bytesize
end
puts zlen($stdin.read) - zlen('')
__END__
下面的内容就是词典了
使用法:
entropy.rb < your_code.rb
就以 Hanoi 塔问题来说 (假设初始圆盘都在中间,需要把所有圆盘移到左边)
圆盘数量为 0 时,那么什么都不用动,问题解决. 假设圆盘数量为 n-1 时问题解决了,那么圆盘数量为 n 时:可以把上面 n-1 个圆盘从中间移动到右边,然后把第 n 个圆盘从中间移动到左边,然后再把那 n-1 个圆盘从右边移动到左边,问题也解决了。
是不是和数学归纳法的证明过程一个模子出来的?写出了递归程序,也可以依样画葫芦用归纳法 (不过一般不是数学归纳法,而是更一般的良序归纳法) 来证明它写对了。很多 LISP 和 ML 的理论书里对递归有更深刻的讨论,有精力的话推荐看看...
如果学过数学归纳法,那么写递归程序就毫无鸭梨...
类也是对象,类的实例变量 和 对象的实例变量没什么区别。
类的实例变量和类变量同样是绑定在类上的,但还是有区别的:
class A
@i = "ivar"
@@i = "class var"
# 实例方法可以访问类变量, 但不能访问类的实例变量
def f
p @i #=> nil
p @@i #=> "class var"
end
end
A.new.f
class B < A
p @i # nil
p @@i # "class var"
end
想避免污染子类的话推荐用类的实例变量,然后用类上的方法访问
class A
# 类上的方法可以访问类的实例变量
def A.i
@i
end
end
IE 解决方法:
<!--[if ie]>
<script>
$('.item:nth-child(odd)').addClass('item-odd')
$('.item:nth-child(even)').addClass('item-even')
</script>
<![end if]-->
Matrix.columns(x).to_a
可以换成 x.transpose
吧?
给定数组里带 nil
怎么办?
循环版:
i = 0
arr.group_by{ i+=1; i%n }.values
这书是蒙人的么...
result = ary.each_slice(10).to_a
engine 是比喻的修辞手法,不用太在意
试过渐变背景但色阶只有 5,没有 lolcat 好看...
嗯嗯,楼上说的对
让我用最客观的方式表达的话:spring 就是一坨屎
赶紧把 markleft 和 markright 名字抢占了
@lgn21st 辛苦了!
nkf 带了一个简单的编码检测,不过没有 icu 的强大,ruby 有个 icu 的绑定 charlock_holmes 可以试试