| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Perl: Общие вопросы > регулярное выражение к строке с повторяющимися бло |
| Автор: allinia 14.10.2008, 13:27 |
| Помогите, пожалуйста, составить регулярное выражение для следующего случая. Есть огромный (100 Мб) текстовый файл однотипных данных, который я считываю как строку. Данные вида: begin typ1 string 1.1 ... string 1.n end begin typ2 string 2.1 ... string 2.n end ... begin typN string N.1 ... string N.n end Все это разбито на строки с различными управляющими символами. Я хочу каждую запись опеределенного типа положить в массив. ('begin typ1 string 1.1 ... string 1.n end', begin typ2 string 2.1 ... string 2.n end',..., begin typN string N.1 ... string N.n end') пробовала так: @result_array = ($orig_text =~ m/(BEGIN\s*$typ\s*[\w\s\d\.\W]*END)/gc); но в первый элемент массива записывается весь текст. Т.е. он берет первый Бегин и самый последний Енд. А как сделать, чтобы он последoвательно записывал все комбинации Бегинов и эндов в соответствующие элементы массива, я никак не могу придумать. Помогите, пожалуйста! |
| Автор: ginnie 14.10.2008, 13:34 | ||
Уважаемая allinia, попробуйте
не понятно только назначение $ (получается подстановка значения переменной $typ), а также \w и \W в одной группе |
| Автор: allinia 14.10.2008, 14:12 |
| ginnie! Спасибо большое, получается! И я ведь сама думала что мне обязательно нужeн знак вопроса, только ставила я его все время не туда! Переменную мне нужно подставлять, так как нужно по-разному обрабатывать данные в зависимости от типа. а \w и \W, потому что в тексте содержится огромное количество всяких управляющих символов, начиная с перевода каретки, перевода строки, всяких эскейпов и т.п и без этого он считывать весь блок ну никак не хочет. А еще вопрос у меня возник, а можно ли как-то сравнить полученные блоки между собой, не используя про этом массивы? В моем случае в каждом блоке содержится дата и время и мне нужно исключить повторяющиейся блоки. Т.е. нужно сравнивать тип, дату и время. Так как Перл лучше всего (быстрее всего) работает со строками, а не с массивами, то хотелось бы по максимуму использовать эту его особенность. |
| Автор: KSURi 14.10.2008, 14:13 |
| У вас в примере текст (BEGIN, END) в нижнем регистре, а в регексе в верхнем. Либо приведите к одному регистру, либо включите режим case-insensitive (//i) |
| Автор: ginnie 14.10.2008, 14:18 |
| allinia, предлагаю сделать чтение из файла построчным и обрабатывать прочитанный целиком блок. При этом формировать из типа, даты и времени ключ хеша для исключения повторений. |
| Автор: allinia 14.10.2008, 14:34 |
| ginnie, я так и делала, пока данные были более-менее обозримыми. Для каждого блока в хэш-таблице был ключ "тип-версия-дата". Только, плохо разбираясь в регулярных выражениях, делила я блоки с помошью функции split(). Но теперь размер получаемых исходных текстовых файлов стал таким оргомным, что потребовалось сначала делить данные по версиям и типам, удаляя при этом повторяющиеся данные. С массивами это работает медленно, хотелось бы оптимизировать, а заодно и научиться работать с регулярными выражениями. Спасибо Вам за подсказку! KSURi, я, конечно же, здесь для примера писала все маленькими буквами, а строчку кода взяла реальную, получилась путаница. В следующий раз буду внимательнее. Спасибо. |
| Автор: arto 14.10.2008, 14:37 |
| perl -MData::Dumper -ne 'chomp; if (m#^begin\s+(\w+)#..m#^end#) { push @{$a->{$e = $1 || $e}},$_ } END { print Dumper $a }' |
| Автор: allinia 14.10.2008, 17:13 | ||||||
amg,
я пробовала модификатор s. В моем случае он не подходит. Не могу четко обьяснить почему, но думаю из-за каких-то особых символов, содержащихся в файле, тот кусок, что мне надо, никак не хотел выделяться. Методом проб и ошибок пришла к варианту \w\W.
Модификатор c используется вместе с модификатором g ,для того чтобы последующий поиск продолжался с того места, где было последнее совпадение. Но Вы правы, в этом случе это излишне.
Даже не знаю, как получше обьяснить, что мне надо. Есть исходный текстовый файл, в котором содержатся блоки данных о некоторых устройствах. Каждый блок может повторяться в текстовом файле, но анализироваться он должен только один раз. Я храню эти блоки в хэш-таблицах, где ключом является связка "номерПрибора-тип-версия-дата". Данные я после всяких манипуляций с ними заношу в соответствующие Ехел таблицы. Пока данных было не такое количество, все работало. Сейчас возникла проблема, что данные инконсистентны, возможно, ошибка в анализаторе, но при таком количестве данных проверить я это физически не могу (например, для одного типа одной версии есть 244 прибора, а типов и версий тоже много). Сейчас мне нужно упростить задачу тем, чтобы хотя бы разделить большой файл со всеми типами на несколько меньших файлов, каждый со своим типом. при этом для ставнения на идентичность блоков (чтобы удалить лишние) мне нужно использовать довольно длинную цепочку - это номер + тип + дата + время + еще несколько параметров, которые в блоке стоят совсем даже не рядом друг с другом. в общем я пока не могу придумать, как это лучше сделать. Я, конечно, могу приложить реальные файлы, но не знаю, поможет ли это вам понять мою задачу, там все по-немецки (я работаю в Германии). Особенно, учитывая, что я сама не могу нормально обьяснить, чего мне надо Я подумаю до завтра, как мне получше сформулировать мою проблему. Большое спасибо за желание помочь! |
| Автор: IceSunrise 14.10.2008, 17:47 |
| Поправьте меня, но в perl нет модификатора 'c' или скажите пожалуйста, где об этом можно почитать? |
| Автор: ginnie 14.10.2008, 17:55 | ||
| allinia, . с модификатором /s должна работать корректно, проверьте еще раз, т.к. \w\W - вариант логически неверный (он работает, но вызывает недоумение у других разработчиков). Модификатор /c используется для сохранения места последнего успешного совпадения при отсутствии совпадения в очередной проверке. Могу предложить сделать структуру в виде вложенных хешей:
это должно упростить проверку целостности данных. Добавлено через 1 минуту и 1 секунду IceSunrise, читайте http://perldoc.perl.org/perlre.html#Modifiers |
| Автор: IceSunrise 14.10.2008, 18:11 |
| ginnie, ага, спасибо, нашел в perlretut, секция Global matching. Нужно сказать никогда не использовал |