سؤال

لدي مجموعة من البيانات في (ما أعتقد أنه) صفيف TCL. أساسا انها في شكل {a {b c} d {e f} g}. وبعد يتغير فقط عميقا، ولكن ليس دائما متداخلا، وهذا يعني، a قد يكون فقط a أو قد يكون {aa bb} أو ربما {}, ، لكن ابدا {aa {bb cc}}. وبعد أريد استخراج هذه الصفيف حتى أتمكن من استخدامه في روبي.

كان فكرتي الأولى، "لا مشكلة، سأكتب القواعد القويلة قليلا لتحليل هذا". لقد قمت بتثبيت جوهرة Treetop، وكتبت محللا، مما يبدو أنه يعمل بشكل جيد. بدأت تواجه مشاكل عندما حاولت استخراج صفيف من الشجرة المحورة. أود أن أفهم أفضل سبب المشاكل وما أقوم به خطأ.

هنا هو رمز المحلل الخاص بي حتى الآن: (tcl_array.treetop)

grammar TCLArray
  rule array
    "{" [\s]* "}" {
      def content
        []
      end
    }
    /
    "{" [\s]* array_element_list [\s]* "}" {
      def content
        array_element_list.content
      end
    }
  end

  rule array_element_list
    array_element {
      def content
        [array_element.content]
      end
    }
    /
    array_element [\s]+ array_element_list {
      def content
        [array_element.content] + array_element_list.content
      end
    }
  end

  rule array_element
    [^{}\s]+ {
      def content
        return text_value
      end
    }
    /
    array {
      def content
        array.content
      end
    }
  end
end

استدعاء p.parse("{a}").content عائدات tcl_array.rb:99:in 'content': undefined local variable or method 'array_element'

يقول المصطلح الأول في Array_Element_List (Array_Element) أن Array_Element هو متغير محلي غير محدد، ولكن من المفترض أن يتم تحديد أساليب Accessor تلقائيا وفقا لوثائق تريتوب.

في وقت سابق، جربت حلا استند إلى قواعد قوية مع عدد أقل من القواعد ولكن أكثر تعقيدا قليلا:

grammar TCLArray
  rule array
    "{" ([\s]* array_element ([\s]+ array_element)* )? [\s]* "}"
  end

  rule array_element
    [^{}\s]+ / array
  end
end

ولكن مع هذا القواعد القواعد، كان لدي مشكلات حيث يبدو أن المحلل المحلل يخلق عدة تعبيرات مختلفة لقاعدة الصفيف على الرغم من أنه لم يستخدم أي تعبيرات بديلة (/). كانت النتيجة أنني لم أستطع معرفة كيفية الوصول إلى أجزاء مختلفة من قاعدة الصفيف لإعادتها كصفيف روبي.

هل كانت مفيدة؟

المحلول

ربما يكون مولد المحلل هو المبالغة في هذه الحالة. إليك محلل نزود نسب منخفض يدويا على أساس هذا محلل JSON من جيمس إدوارد جراي II:

#!/usr/bin/env ruby
# based on James Edward Gray II's solution to the Parsing JSON
#   Ruby Quiz #155: <http://RubyQuiz.Com/quiz155.html>

require 'strscan'

class TclArrayParser < StringScanner
  def parse
    parse_value
  ensure
    eos? or error "Unexpected data: '#{rest}'"
  end

  private

  def parse_value
    trim_space
    parse_string or parse_array
  ensure
    trim_space
  end

  def parse_array
    return nil unless scan(/\{\s*/)
    array = []
    while contents = parse_value
      array << contents
    end
    scan(/\}/) or error('Unclosed array')
    array
  end

  def parse_string
    scan(/[^{}[:space:]]+/)
  end

  def trim_space
    skip(/\s*/)
  end

  def error(message)
    pos = if eos? then 'end of input' else "position #{self.pos}" end
    raise ParseError, "#{message} at #{pos}"
  end

  class ParseError < StandardError; end
end

إليك TestSuite:

require 'test/unit'
class TestTclArrayParser < Test::Unit::TestCase
  def test_that_an_empty_string_parses_to_nil
    assert_nil TclArrayParser.new('').parse
  end
  def test_that_a_whitespace_string_parses_to_nil
    assert_nil TclArrayParser.new("  \t  \n  ").parse
  end
  def test_that_an_empty_array_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new('{}').parse
  end
  def test_that_an_empty_array_with_whitespace_at_the_front_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new(' {}').parse
  end
  def test_that_an_empty_array_with_whitespace_at_the_end_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new('{} ').parse
  end
  def test_that_an_empty_array_with_whitespace_inside_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new('{ }').parse
  end
  def test_that_an_empty_array_surrounded_by_whitespace_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new(' {} ').parse
  end
  def test_that_an_empty_array_with_whitespace_at_the_front_and_inside_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new(' { }').parse
  end
  def test_that_an_empty_array_with_whitespace_at_the_end_and_inside_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new('{ } ').parse
  end
  def test_that_an_empty_array_surrounded_by_whitespace_with_whitespace_inside_parses_to_an_empty_array
    assert_equal [], TclArrayParser.new(' { } ').parse
  end
  def test_that_a_sole_element_parses
    assert_equal 'a', TclArrayParser.new('a').parse
  end
  def test_that_an_array_with_one_element_parses
    assert_equal ['a'], TclArrayParser.new('{a}').parse
  end
  def test_that_a_nested_array_parses
    assert_equal [[]], TclArrayParser.new('{{}}').parse
  end
  def test_that_a_nested_array_with_one_element_parses
    assert_equal [['a']], TclArrayParser.new('{{a}}').parse
  end
  def test_that_whitespace_is_ignored
    assert_equal [], TclArrayParser.new('     {     }     ').parse
  end
  def test_that_complex_arrays_parse_correctly
    assert_equal ['a', %w[b c], 'd', %w[e f], 'g'], TclArrayParser.new('{a {b c} d {e f} g}').parse
    assert_equal [%w[aa bb], %w[b c], 'd', %w[e f], 'g'], TclArrayParser.new('{{aa bb} {b c} d {e f} g}').parse
    assert_equal [[], %w[b c], 'd', %w[e f], 'g'], TclArrayParser.new('{{} {b c} d {e f} g}').parse
    assert_equal [[], ['b', 'c'], 'd', ['e', 'f'], 'g'], TclArrayParser.new("\n{\n{\n}\n{\nb\nc\n}\nd\n{\ne\nf\n}\ng\n}\n").parse
  end
end

نصائح أخرى

وإذ تلاحظ هذا للإشارة، لكنني أصدرت فقط جوهرة لتحليل TCL بسيط.

https://github.com/julik/tickly.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top