• List to Regexp at 2012年11月11日

    #13 楼 @Los 这个实现有点 quick and dirty, 还不好做这个优化,有空我会试试

  • List to Regexp at 2012年11月07日

    整成一个 gem 了 ...

    gem ins regexp_optimized_union
    
    require 'regexp_optimized_union'
    Regexp.optimized_union %w[foobar foobaz foobarbaz]
    
  • List to Regexp at 2012年11月07日

    @hooopo

    整了一个 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
    
  • 老赵同学的一道编程题 at 2012年11月06日

    @hooopo @fsword 其实 1.9 区别也不大..

    doc.gsub(/(\b\w)(\w{2,})(\w\b)/) { $1 + $2.chars.to_a.shuffle.join + $3 }
    

    gsub 里可以用 $1, $2, ...

  • 老赵同学的一道编程题 at 2012年11月06日

    #12 楼 @hooopo 是的... 1.9 上面 look ahead 还是有点限制

  • 老赵同学的一道编程题 at 2012年11月06日
    doc.gsub(/(?<=\b\w)\w{2,}(?=\w\b)/) {|s| s.chars.to_a.shuffle.join }
    

    p.s. 需要 Ruby 2.0 Onigmo

  • List to Regexp at 2012年11月06日

    好吧看了编译出来的 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 个子的话,做这种优化会快一倍多点的样子,但是短的就不清楚了

    可以一做...

  • List to Regexp at 2012年11月05日

    做了有用么?貌似正则引擎已经做了提取公共子表达式的优化了?

  • elsif 和 perl 一样,没必要发明个新的...

  • Ruby 2.0 新功能演示 at 2012年11月03日

    Ruby 1.9 的主要 IO 函数已经是不需要进程内同步了,爬虫或 http 服务器已经可以用多线程提高速度了。

  • Ruby 2.0 preview1 is out at 2012年11月02日

    什么时候能请 koichi 来一次就好了

  • html5 的话是用音频或者视频的 video_or_audio.currentTime = x 跳转到第 x 秒的

    但是字幕和时间数据如何对应是个问题,如果一个 video 已经有字幕文件,可以解析字幕文件把时间轴弄出来,否则就要用类似卡拉 OK 的制作工具来录入时间轴了。

    @hlxwell 做过 web 版时间轴的录入工具哦。做法就是把音频慢放 (这也是有一个工具可以转换的), 一个人每听一句话就按一下空格键把时间对上,一般还要设一个反映延迟来修正录入后的时间数据。

  • thePlant 的 @sunfmin 做过,每个词还能链接到词典解释的...

  • 终于阿!

  • Cocoa 应用程序里嵌入 Ruby at 2012年10月31日

    @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
    
  • 递归程序有点不好写阿? at 2012年10月31日

    就以 Hanoi 塔问题来说 (假设初始圆盘都在中间,需要把所有圆盘移到左边)

    圆盘数量为 0 时,那么什么都不用动,问题解决. 假设圆盘数量为 n-1 时问题解决了,那么圆盘数量为 n 时:可以把上面 n-1 个圆盘从中间移动到右边,然后把第 n 个圆盘从中间移动到左边,然后再把那 n-1 个圆盘从右边移动到左边,问题也解决了。

    是不是和数学归纳法的证明过程一个模子出来的?写出了递归程序,也可以依样画葫芦用归纳法 (不过一般不是数学归纳法,而是更一般的良序归纳法) 来证明它写对了。很多 LISP 和 ML 的理论书里对递归有更深刻的讨论,有精力的话推荐看看...

  • 递归程序有点不好写阿? at 2012年10月30日

    如果学过数学归纳法,那么写递归程序就毫无鸭梨...

  • 关于 Ruby 类的实例变量 at 2012年10月30日

    类也是对象,类的实例变量 和 对象的实例变量没什么区别。

    类的实例变量和类变量同样是绑定在类上的,但还是有区别的:

    • 类变量可以从实例方法访问,类的实例变量不能
    • 类变量子类可见
    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]-->
    
  • 一道编程题 at 2012年10月30日

    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 好看...

  • aop 功能似乎不如 spring at 2012年10月26日

    嗯嗯,楼上说的对

    让我用最客观的方式表达的话:spring 就是一坨屎

  • 赶紧把 markleft 和 markright 名字抢占了

  • @lgn21st 辛苦了! 🏆

  • nkf 带了一个简单的编码检测,不过没有 icu 的强大,ruby 有个 icu 的绑定 charlock_holmes 可以试试