Sha256: 87d81813934473a15e5ef2d9df181497ea12419aa8e12313f63aefe0807d62e8

Contents?: true

Size: 1.57 KB

Versions: 4

Compression:

Stored size: 1.57 KB

Contents

module Enumerable
  def sort_by_alphanum
    sort do |a, b|
      if block_given?
        grouped_compare(yield(a), yield(b))
      else
        grouped_compare(a, b)
      end
    end
  end

  def sort_by_alphanum!
    sort! do |a, b|
      if block_given?
        grouped_compare(yield(a), yield(b))
      else
        grouped_compare(a, b)
      end
    end
  end

  private

  ALL_NUM = /\d+/
  ALL_ALPHA = /[A-Za-z]+/
  NON_ALPHANUM = /[^A-Za-z0-9]+/

  def grouped_compare(a, b)
    a_scanner = StringScanner.new(a)
    b_scanner = StringScanner.new(b)
    # each loop has to do exactly 1 non-nil-scan on both scanners or return a non-zero value.
    loop do
      ret = \
        if a_scanner.eos?
          -1
        elsif b_scanner.eos?
          1
        elsif (a_chunk = a_scanner.scan(ALL_NUM))
          if (b_chunk = b_scanner.scan(ALL_NUM))
            if a_chunk.to_i != b_chunk.to_i
              a_chunk.to_i <=> b_chunk.to_i
            else # 03 vs 3
              a_chunk <=> b_chunk
            end
          elsif b_scanner.scan(ALL_ALPHA)
            -1
          else # NON_ALPHANUM
            1
          end
        elsif (a_chunk = a_scanner.scan(ALL_ALPHA))
          if (b_chunk = b_scanner.scan(ALL_ALPHA))
            a_chunk <=> b_chunk
          else # ALL_NUM or NON_ALPHANUM
            1
          end
        else # NON_ALPHANUM
          a_chunk = a_scanner.scan(NON_ALPHANUM)
          if (b_chunk = b_scanner.scan(NON_ALPHANUM))
            a_chunk <=> b_chunk
          else
            -1
          end
        end
      return ret if ret != 0
    end
  end
end

Version data entries

4 entries across 4 versions & 1 rubygems

Version Path
roqua-support-0.4.6 lib/roqua/core_ext/enumerable/sort_by_alphanum.rb
roqua-support-0.4.5 lib/roqua/core_ext/enumerable/sort_by_alphanum.rb
roqua-support-0.4.4 lib/roqua/core_ext/enumerable/sort_by_alphanum.rb
roqua-support-0.4.3 lib/roqua/core_ext/enumerable/sort_by_alphanum.rb