Ruby заполняет 2 dim массива динамически - PullRequest
0 голосов
/ 24 сентября 2019

Я работаю над анализатором для анализа кода SQL, поэтому пытаюсь разобраться со всеми комментариями блока.Я придумала решение для обработки регулярных выражений по индексу, чтобы увидеть, находится ли он внутри блока комментариев, и для этой цели пытаюсь заполнить 2 dim-массив в приведенном ниже коде, где второй элемент будет буквальным, скажем, s .Не уверен, что это выполнимо.Я попробовал один драгоценный камень, но он потерпел неудачу.Моя цель получить массив заполненный как

all =[[9,'s'],[19,'s'],[24,'s']]
, ссылаясь на пример ниже.Конечная цель состоит в том, чтобы обработать унаследованный код SQL (большая его часть ..), чтобы найти активные строки с конкретными ключевыми словами.Бест

x = 'line:xss /*   */   /*   /*  CODE_Comment */  '
     puts x

    i = -1
    all = [[],[]]
    while i = x.index('/*',i+1)             
do   all << i   ####<@>>< how to add literal to second element ???
    end
    puts all  

1 Ответ

2 голосов
/ 24 сентября 2019

Вы можете сделать следующее.

str = 'line:xss /*   */   /*   /*  CODE_Comment */  '

str.gsub(/\/\*/).with_object([]) { |_,a| a << [Regexp.last_match.begin(0), 's'] }
  #=> [[9, "s"], [19, "s"], [24, "s"]] 

Шаги следующие:

enum1 = str.gsub(/\/\*/)
  #=> #<Enumerator: "line:xss /*   */   /*   /*  CODE_Comment */  "
  #     :gsub(/\/\*/)>

Если выИзучите документ для String # gsub . Вы увидите, что когда gsub имеет один аргумент и не имеет блока (форма метода 4 th ), он возвращает перечислитель.Любопытно, что при таком способе он не имеет ничего общего с заменой подстрок другими подстроками.

enum1 не делает ничего, кроме генерации совпадений:

enum1.next #=> "/*" 
enum1.next #=> "/*" 
enum1.next #=> "/*" 
enum1.next #=> StopIteration (iteration reached an end)

См. Enumerator #следующий .Прежде чем продолжить, давайте сбросим перечислитель:

enum1.rewind

См. Перечислитель # перемотка .Затем

enum2 = enum1.with_object([])
  #=> #<Enumerator: #<Enumerator: "line:xss /*   */   /*   /*  CODE_Comment */  "
  #     :gsub(/\/\*/)>:with_object([])> 
enum2.next #=> ["/*", []] 
enum2.next #=> ["/*", []] 
enum2.next #=> ["/*", []] 
enum2.next #=> StopIteration (iteration reached an end) 
enum2.rewind

enum2 (который можно рассматривать как составной перечислитель ) теперь генерирует элементы, которые он передает блоку.Значения этих элементов фиксируются переменными блока, а затем выполняется расчет блока.Мы можем добавить несколько операторов puts, чтобы проверить вычисляемые значения.

enum2.each do |_,a|
  puts "\n_ = #{_}, a = #{a}"
  md = Regexp.last_match
  b= md.begin(0) 
  puts "md = #{md}, b = #{b}"
  a << [b, 's']
  puts "a = #{a}"
end
  #=> [[9, "s"], [19, "s"], [24, "s"]] 

и распечатать

_ = /*, a = []
md = /*, b = 9
a = [[9, "s"]]

_ = /*, a = [[9, "s"]]
md = /*, b = 19
a = [[9, "s"], [19, "s"]]

_ = /*, a = [[9, "s"], [19, "s"]]
md = /*, b = 24
a = [[9, "s"], [19, "s"], [24, "s"]]

Я использовал подчеркивание (допустимая локальная переменная) в качестве заполнителядля первой переменной блока, чтобы показать читателю, что она не используется в вычислении блока (обычно используемое соглашение).Для построения массива нам понадобится смещение в строке str, где это совпадение было сделано.Для этого мы сначала получаем экземпляр MatchData, сгенерированный этим соответствием (см. Regexp :: last_match ), а затем используем метод LastMatch # begin , чтобы получить смещение для началаматч.Наконец, мы добавляем желаемый массив из 2 элементов к a.

Значение Regexp.last_match хранится в глобальной переменной $~, так что эта переменная иногда используется вместо Regexp.last_match.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...