Получить только значения Hexadecima (байты) из массива в ruby

У меня есть следующий массив, который представляет десятичные значения символов ASCII и не ASCII.

a=[32, 57, 50, 32, 56, 51, 32, 65, 52, 130, 0, 101, 131, 69, 72, 38, 146, 89, 9]

Преобразование в char выглядит следующим образом

a.map{|b| b.chr}
=> [" ", "9", "2", " ", "8", "3", " ", "A", "4", "\x82", "\x00", "e", "\x83", "E", "H", "&", "\x92", "Y", "\t"]

и соединяясь, чтобы создать строку с байтами (пары шестнадцатеричных чисел, [0-9A-F]), я делаю это:

a.map{|b| b.chr}.join
=> " 92 83 A4\x82\x00e\x83EH&\x92Y\t"

Затем я хочу удалить строку, начинающуюся с первого не ASCII-значения, которое является \x82, и мне это нравится, но ничего не происходит.

a.map{|b| b.chr}.join.gsub(/\\x.*/,"")
=> " 92 83 A4\x82\x00e\x83EH&\x92Y\t"

Мой ожидаемый вывод - иметь только шестнадцатеричные числа ниже:

92 83 A4

Как я могу это сделать?

Спасибо за любую помощь.

ОБНОВИТЬ

Тестируя с большим массивом, как показано ниже, я вижу, что вывод верен только для решения @ rewritten. Выход для этого нового массива: " 92 83 49 26 92 59 00"

a=[32, 57, 50, 32, 56, 51, 32, 52, 57, 32, 50, 54, 32, 57, 50, 32, 53, 57, 
32, 48, 48, 0, 0, 0, 0, 2, 130, 0, 0, 8, 254, 70, 124, 0, 6, 0, 3, 0, 3, 
27, 0,2, 27, 3, 0, 227, 7, 1, 14, 17, 33, 0, 28, 14, 47, 38, 146, 89, 9]

a.map(&:chr).join.match(/^( \X\X)+/)[0]            # rewritten's solution
a.map(&:chr).take_while(&"\x80".method(:>)).join   # Aleksei's solution
a.map(&:chr).take_while(&:ascii_only?).join        # cremno's solution

irb(main): a.map(&:chr).join.match(/^( \X\X)+/)[0]
=> " 92 83 49 26 92 59 00"

irb(main): a.map(&:chr).take_while(&"\x80".method(:>)).join
=> " 92 83 49 26 92 59 00\x00\x00\x00\x00\x02"

irb(main): a.map(&:chr).take_while(&:ascii_only?).join
=> " 92 83 49 26 92 59 00\x00\x00\x00\x00\x02"

Спасибо всем за помощь.

2 ответа

Решение

Учитывая комментарий, я предполагаю, что вы действительно хотите спросить о соответствии шаблона "пробел, гекс, шестнадцатеричный" до первого несоответствия.

Это было бы как

a.map(&:chr).join.match(/^( \X\X)+/)[0]

Он использует специальные \X заполнитель для регулярных выражений, совпадающих с шестнадцатеричными цифрами u̶p̶p,e)r̶c̶a̶s̶e̶ (0-9,AF,af).


Дополнительная информация:

Опять же, исходя из моей интерпретации вопроса, если исходный массив длинный (или поток), нет необходимости использовать все это. Вам лучше прекратить генерировать символы как можно скорее:

hexs = "0123456789ABCDEF".split.map(&:ord)
a.
  lazy.
  each_slice(3).
  take_while { |spc, h1, h2| spc == 32 && hexs.include?(h1) && hexs.include?(h2) }.
  flat_map(&:chr).
  to_a.
  join

Таким образом, любая часть вашего целочисленного массива даже не учитывается.

Просто отфильтруйте его перед объединением массива в строку:

[" ", "9", "2", " ", "8", "3", " ", "A", "4", "\x82", "\x00"].
  take_while(&"\x80".method(:>))
#⇒ [" ", "9", "2", " ", "8", "3", " ", "A", "4"]

Затем делайте все, что вы хотите с результирующим массивом.

Другие вопросы по тегам