Разбор текста в Ruby

Я работаю над сценарием для импорта информации о компонентах для SketchUp. Очень полезный человек на их странице справки помог мне создать тот, который работает с «отредактированным» построчным текстовым файлом. Теперь я готов перейти на следующий уровень — импортировать напрямую из исходного файла, созданного FreePCB.

Часть файла, которую я хочу использовать, приведена ниже: «sample_1.txt».

[parts]

part: C1
  ref_text: 1270000 127000 0 -7620000 1270000 1
  package: "CAP-AX-10X18-7X"
  value: "4.7pF" 1270000 127000 0 1270000 1270000 1
  shape: "CAP-AX-10X18-7"
  pos: 10160000 10160000 0 0 0

part: IC1
  ref_text: 1270000 177800 270 2540000 2286000 1
  package: "DIP-8-3X"
  value: "JRC 4558" 1270000 177800 270 10668000 508000 0
  shape: "DIP-8-3"
  pos: 2540000 27940000 0 90 0

part: R1
  ref_text: 1270000 127000 0 3380000 -600000 1
  package: "RES-CF-1/4W-4X"
  value: "470" 1270000 127000 0 2180000 -2900000 0
  shape: "RES-CF-1/4W-4"
  pos: 15240000 20320000 0 270 0

Слово [части] в скобках — это просто заголовок раздела. Информация, которую я хочу извлечь, это условное обозначение, форма, положение и поворот. У меня уже есть код для этого из переформатированного текстового файла с использованием IO.readlines(file).each{ |line| data = line.split(" ");.

Мой текущий метод использует текстовый файл, переформатированный следующим образом: «sample_2.txt»

C1 CAP-AX-10X18-7 10160000 10160000 0 0 0
IC1 DIP-8-3 2540000 27940000 0 90 0
R1 RES-CF-1/4W-4 15240000 20320000 0 270 0

Затем я использую массив для извлечения данных [0], данных [1], данных [2], данных [3] и данных [5]. Плюс дополнительный шаг, чтобы добавить «.skp» в конец имени пакета, чтобы сценарий мог вставлять компоненты с тем же именем, что и пакет.

Я хотел бы извлечь информацию из 1-го примера, не переформатируя файл, как в случае со 2-м примером. т. е. я знаю, как вытащить информацию из одной строки, разделенной пробелами. Как мне это сделать, когда текст для одного массива появляется более чем в одной строке?

Заранее благодарю за любую помощь ;-)

РЕДАКТИРОВАТЬ: Ниже приведен полный код для анализа «sample_2.txt», который был переформатирован до запуска скрипта.

    # import.rb - extracts component info from text file

    # Launch file browser
    file=UI.openpanel "Open Text File", "c:\\", "*.txt"

    # Do for each line, what appears in braces {}
    IO.readlines(file).each{ |line| data = line.split(" ");

    # Append second element in array "data[1]", with SketchUp file extension
    data[1] += ".skp"

    # Search for component with same name as data[1], and insert in component browser
    component_path = Sketchup.find_support_file data[1] ,"Components"
    component_def = Sketchup.active_model.definitions.load component_path

    # Create transformation from "origin" to point "location", convert data[] to float
    location = [data[2].to_f, data[3].to_f, 0]
    translation = Geom::Transformation.new location

    # Convert rotation "data[5]" to radians, and into float
    angle = data[5].to_f*Math::PI/180.to_f
    rotation = Geom::Transformation.rotation [0,0,0], [0,0,1], angle

    # Insert an instance of component in model, and apply transformation
    instance = Sketchup.active_model.entities.add_instance component_def, translation*rotation

    # Rename component 
    instance.name=data[0]

    # Ending brace for "IO.readlines(file).each{"
    }

В результате получается следующий вывод: от запуска «import.rb» до открытия «sample_2.txt».

    C1 CAP-AX-10X18-7 10160000 10160000 0<br>IC1 DIP-8-3 2540000 27940000 90<br>R1 RES-CF-1/4W-4 15240000 20320000 270

Я пытаюсь получить те же результаты из неотредактированного исходного файла «sample_1.txt» без дополнительного шага по удалению информации из файла с помощью блокнота «sample_2.txt». Ключевые слова, за которыми следует двоеточие (part, shape, pos), появляются только в этой части документа и больше нигде, но... документ довольно длинный, и мне нужно, чтобы скрипт игнорировал все, что появляется до и после раздела [parts].


person tahwos    schedule 13.05.2011    source источник


Ответы (2)


Ваш вопрос не ясен, но это:

text.scan(/^\s+shape: "(.*?)"\s+pos: (\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/)

дам тебе:

[["CAP-AX-10X18-7", "10160000", "10160000", "0", "0", "0"],
 ["DIP-8-3", "2540000", "27940000", "0", "90", "0"],
 ["RES-CF-1/4W-4", "15240000", "20320000", "0", "270", "0"]]

Добавлено после изменения вопроса

Этот:

text.scan(/^\s*part:\s*(.*?)$.*?\s+shape:\s*"(.*?)"\s+pos:\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/m)

дам тебе

[["C1", "CAP-AX-10X18-7", "10160000", "10160000", "0", "0", "0"],
 ["IC1", "DIP-8-3", "2540000", "27940000", "0", "90", "0"],
 ["R1", "RES-CF-1/4W-4", "15240000", "20320000", "0", "270", "0"]]

Второй раз добавлено после изменения вопроса

Этот:

text.scan(/^\s*part:\s*(.*?)$.*?\s+shape:\s*"(.*?)"\s+pos:\s*(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)/m)

позволит вам фиксировать числа, даже если они отрицательные.

person sawa    schedule 13.05.2011
comment
@sawa Это выглядит достаточно просто ... чтобы уточнить, мне нужно манипулировать данными, следующими за part:, shape: и pos:, как с одной строкой, независимо от того, присутствуют ли другие элементы, то есть package:, value:, ref_text :. - person tahwos; 13.05.2011
comment
Вот так может...? text.scan(/^part: "(.*?)"\s+shape: "(.*?)"\s+pos: (\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/) - person tahwos; 13.05.2011
comment
Я не понимаю, как part: захвачено. У вас есть в тексте C1, IC1, R1, а затем ваш ожидаемый результат будет C1, C2, C3. Вы должны быть осторожны с точностью примеров, которые вы приводите в вопросе. - person sawa; 13.05.2011
comment
Исправлено - у меня было открыто 2 окна, пробовал другой код, и скопировал не с того. По сути, это было то же самое, я просто немного поработал с текстовым файлом, чтобы увидеть результаты. Спасибо, что поймали это. Что касается того, как часть захвачена, поэтому я перепостил вот так? Ваш пример начинается с ^ \s+shape: "(.*?)"... начала строки или строки, за которой следует пробел + форма: (любой символ, кроме новой строки, 0 или более) - есть ли причина, по которой я не могу развернуть его назад, чтобы подобрать часть: также? - person tahwos; 13.05.2011
comment
ОК - (/^part: (.*)/) работает сам по себе, но не с включенным остальным кодом, который тоже работает нормально - спасибо! - person tahwos; 14.05.2011
comment
@sawa - это сработало, мне просто нужно проверить это на большем файле. - person tahwos; 14.05.2011
comment
@sawa - тестирование на большом файле работало с регулярным выражением, работающим в одиночку, с одной небольшой заминкой, отрицательные значения pos: заставляют код переходить к следующему pos:, который возвращает все положительные значения, и, очевидно, все данные между ними возвращаются для предыдущий shape:. Как я уже сказал, второстепенное... не имеет большого значения, чтобы убедиться, что все положительно, до запуска сценария. Сейчас тестирую в полном скрипте... - person tahwos; 14.05.2011
comment
@sawa - вывод остался прежним - отрицательные значения были пропущены до следующего положительного результата. Однако оба примера хорошо фиксируют совпадения. - person tahwos; 14.05.2011
comment
@tahwos Что ты имеешь в виду под негативом? - person sawa; 14.05.2011
comment
pos: 243586000 -14986000 0 180 0 Вторая запись приводит к тому, что весь элемент игнорируется, и он возвращается при следующем совпадении со всеми положительными записями для этой части выражения. Может быть, я просто тестирую это - все еще пишу код для полного теста. Я не могу просто скопировать и вставить его в исходный код и заставить его работать. - person tahwos; 14.05.2011
comment
@tahwos Я должен сказать, что примеры, которые вы привели, на самом деле не отражают того, о чем вы спрашиваете. Вы исправили значения деталей, и теперь оказывается, что вы не показывали примеры с отрицательными значениями чисел. Вы должны быть осторожны с примерами. Я снова обновляю свой ответ. Обратите внимание, что кто-то (не я) проголосовал за закрытие вашего вопроса. Это потому, что это написано не с осторожностью. Вы не можете требовать ответа, качество которого намного превосходит качество вашего вопроса. - person sawa; 14.05.2011
comment
Как я уже говорил в предыдущем ответе, ваши примеры были удовлетворительными в части сбора данных, и что ранее неизвестные результаты, касающиеся отрицательных чисел, были приемлемым конфликтом (я могу просто переместить источник всего проекта, чтобы убедиться, что все положительно начать с). Однако в вашем последнем примере отрицательные значения были преобразованы в положительные, что не является приемлемым конфликтом. - person tahwos; 14.05.2011
comment
@sawa - я прокручивал страницу вверх и вниз и не вижу ничего, что указывало бы на голосование за закрытие этого вопроса. Возможно, я ищу не в том месте, но в любом случае ваше второе исполнение кода, включающее сопоставление атрибута part:, — это то, над чем я работал, чтобы интегрировать регулярное выражение в мой исходный код. В нынешнем виде мое текущее состояние прогресса в любом случае было бы совершенно новым вопросом, и вы невероятно помогли мне зайти так далеко. Спасибо! ;-) - person tahwos; 14.05.2011
comment
Кстати... Я опубликовал первые 3 части вопроса, а не весь файл, который содержит 239 частей и более 17 000 строк информации (из вежливости). Итак, да, еще раз, я очень доволен результатами вашей второй итерации выражения - вы смогли представить решение в одной строке кода, который прочитал весь документ и извлек только ту информацию, которая мне нужна. - person tahwos; 14.05.2011
comment
@tahwos Как вы заметили, в моем ответе была ошибка. Я должен был поместить -? в круглые скобки. Я исправил это выше. Теперь он должен работать правильно. - person sawa; 14.05.2011
comment
@sawa - Да, это помогло, все числа были записаны в том виде, в каком они появляются в исходном файле. Еще раз спасибо - Тавос - person tahwos; 14.05.2011

Не уверен, что именно вы спрашиваете, но, надеюсь, это поможет вам получить то, что вы ищете.

parts_text = <<EOS
[parts]

part: **C1**
  ref_text: 1270000 127000 0 -7620000 1270000 1
  package: "CAP-AX-10X18-7X"
  value: "4.7pF" 1270000 127000 0 1270000 1270000 1
  shape: "**CAP-AX-10X18-7**"
  pos: **10160000** **10160000** 0 **0** 0

part: **IC1**
  ref_text: 1270000 177800 270 2540000 2286000 1
  package: "DIP-8-3X"
  value: "JRC 4558" 1270000 177800 270 10668000 508000 0
  shape: "**DIP-8-3**"
  pos: **2540000** **27940000** 0 **90** 0

part: **R1**
  ref_text: 1270000 127000 0 3380000 -600000 1
  package: "RES-CF-1/4W-4X"
  value: "470" 1270000 127000 0 2180000 -2900000 0
  shape: "**RES-CF-1/4W-4**"
  pos: **15240000** **20320000** 0 **270** 0
EOS

parts = parts_text.split(/\n\n/)
split_parts = parts.each.map { |p| p.split(/\n/) }
split_parts.each do |part|
  stripped = part.each.collect { |p| p.strip }
  stripped.each do |line|
    p line.split(" ")
  end
end

Это можно было бы сделать намного эффективнее с помощью регулярных выражений, но я выбрал методы, с которыми вы, возможно, уже знакомы.

person ezkl    schedule 13.05.2011
comment
Я не боюсь регулярных выражений, на самом деле я думаю, что их легче читать. - person tahwos; 13.05.2011
comment
Примечание для себя, не нажимайте Enter при ответе. В вашем примере, если некоторые элементы из исходного текстового файла отсутствуют, то есть пакет:, значение:, будет ли поврежден весь массив? - person tahwos; 13.05.2011
comment
Нет, элементы не важны. Разделителями являются символы новой строки (/\n/). Между каждой группой есть 2 разрыва строки. Внутри каждой группы есть один разрыв строки между каждой строкой. Самый внутренний блок удаляет пробелы с начала и конца каждой строки и разбивает строку на пробелы. - person ezkl; 13.05.2011
comment
Я думаю, именно поэтому это не имело смысла — они должны быть релевантными, потому что, если у других элементов нет значений, они не существуют в текстовом файле. т. е. Интересующие элементы — это единственное, что статично и надежно, чтобы кто-то другой мог использовать скрипт — part:, shape: и pos: всегда есть — ref_text:, package: и value: может не быть. В идеальном документе все сущности существовали бы и работали в самых простых терминах. Из того, что я вижу в вашем примере, если некоторые из них отсутствуют (скорее всего, в середине), то их относительное положение не будет совпадать от группы к группе. - person tahwos; 14.05.2011
comment
Приведенный выше код выдал эту ошибку... test_other.rb:27:in `each': блок не указан (LocalJumpError) - person tahwos; 21.05.2011