LINUX.ORG.RU

perl


0

0

Можно ли perl'лом парсить огромные файлы? Я тут немного посмотрел и он очень удобен, но хочется также функциональности cat file | sed 's///g'..

Правда нужно еще выдирание частей регэкспа в переменные и проверка их поэтому и остановился на Perl.

Но пугают сопособы парсинга в туториалах...

open(INFO, $file); # Open the file
@lines = <INFO>; # Read it into an array

500 Mb'тный файл туда не поместится...

Можно ли читать линия по линии? А если весь 500 Mb'тный файл - одна линия? Можно ли оперировать regexp'ами на на таблице переменных а прямиком на потоке?

Конечно лучше "читать по линиям"! ;)
Читай книжки по перлу

open(INFO, $file) or die;
while($line = <INFO>){
 # do what you need whith $line
}
close(INFO);

Mrak ★★★
()

Читать по линии:

open ($fh, "<file.dat") or die "cannot open file";
while (<$fh>){
 .... что должен делать скрипт ...
 .... например ....
 print $_ . "\n";
}

Со стандартного ввода (например, поток через pipe):

while (<>){
   s/a/A/g;
   print;
}

octy ★★
()
Ответ на: комментарий от octy

Это хорошо. :)

А вот как оперировать на потоке в стиле sed'а? Просто мне надо кое-что сделать с гигантскими файлами xml и там в принципе отдельные линии небольшие, но чем черт не шутит, может там оказаться и гигантская однолинеевая дура... :(

dissident ★★
() автор топика
Ответ на: комментарий от dissident

То есть getc и seek это понятно, но это же не то.. Я же не буду накладывать регэкспы на отдельный char'ы или ездить по файлу seek'ами в стиле C и искать. :\

dissident ★★
() автор топика
Ответ на: комментарий от dissident

Т.е. что значит как?

Совсем простой пример: дано: заменить в файле все строки 'tr' на 'TR'.

1. Файл replace.pl

use strict;
use warnings;

# читаем по строке из stdin
while (<>){
  # производим замену в переменной $_, которую можно не указывать
  s/tr/TR/g;
  # печатаем измененную строку в stdout
  print;
}

2. Команда будет что-то вроде 

cat file.xml | replace.pl > newfile.xml

Одним словом, читай книжки. )

octy ★★
()
Ответ на: комментарий от octy

> # читаем по строке из stdin
> while (<>){
а если в строке куча мегабайт? :\

PS не я эти файлы выдумал. :|

PPS А и еще как для каждого регекспа что-то сделать?

в таком примерно ключе:

while (<>) {
foreach ([0-9+]) {
if ($i = 2)
printf ....
}
}

?

dissident ★★
() автор топика
Ответ на: комментарий от dissident

> foreach ([0-9+]) {
>     if ($i = 2)
в смысле if ($1 == 2)

dissident ★★
() автор топика
Ответ на: комментарий от dissident

Хех а sed то этого тоже не умеет...

first, `sed' reads one line from the input stream, removes any
trailing newline, and places it in the pattern space.

Эх..

dissident ★★
() автор топика
Ответ на: комментарий от octy

<> это вовсе не обязательно стдин.
стдин это <STDIN>... а <> это поочередно читать построчно из всех файлов поданных с консоли аргументами..
например ./script.pl file1 file2 file3

godexsoft
()

парсить строку на части это можно конечно... легче всего читать побайтово и собирать строку например длинной в 1024 байта.
потом делать с этой строкой чтото, а потом все по новой :)

godexsoft
()
Ответ на: комментарий от godexsoft

Сформулирую ка я чего хочу.. Может хотя бы поможет тот факт что сформулирую. ;) (Perl впервые увидел сегодня с утра).

Имея в большом упрощении два файла:

1:
d1-1=.. d1-2=.. d2-1=.. d3-1=..

2:
d1-1=.. d2-1=.. d2-2=..

Хотелось бы получить один файл:

d1-1=.. d1-2=.. d2-1=.. d3-1=.. d4-1=.. d5-1=.. d5-2=..

При этом хотелось бы действительно убедиться в мощности перла, а не ковыряться со split'ом и разделителями (между dx-y множество мусора)

Думаю что достаточно было бы сделать так:

1. Проехать по файлу 1 и создать таблицу "первых" чисел в "x-y"
2. Проехаться по нему снова и соответственно добавлять разные вещи..

А вообще круче всего было бы иметь

s/d([0-9])-[0-9]/{ (\1 == x) ? smth : smth_else }/g

но так наверное нельзя. :\

хотя ситерировать по группам ведь наверное можно?

dissident ★★
() автор топика
Ответ на: комментарий от dissident

>А вообще круче всего было бы иметь

>s/d([0-9])-[0-9]/{ (\1 == x) ? smth : smth_else }/g

Можно, но не совсем так :)

Используй модификатор "e":

s/d([0-9])-[0-9]/$1 == $x ? smth : smth_else/ge

Хинт: "==" - сравнение для ЧИСЕЛ, "eq" - для строк.

Хинт2: прочитай про хеши. Они тебе похоже и нужны.

roller ★★★
()
Ответ на: комментарий от roller

Чудесно, этого мне не хватало в sed. ;)

Еще бы возможность легко ситерировать по всем найденным субгруппам.. Попробовал для тесту:

s/([0-9])/$1 + 1/ge;
foreach $i (1 .. $#+) {
   print "$i\n";
}

да делает что-то не совсем то...



dissident ★★
() автор топика
Ответ на: комментарий от dissident

>да делает что-то не совсем то...

А чего хотелось то?

Если сделаешь:

$str =~ s/([0-9])/$1 + 1/ge;

то в $str будут уже заменены все цифры на числа на единицу больше.

Т.е. "ab2c5" даст "ab3c6"

roller ★★★
()
Ответ на: комментарий от roller

Хотелось бы перед заменой все эти заменненные числа куда-нибудь выдрать. Еще точнее хотелось бы найти их максимум перед заменой.

dissident ★★
() автор топика
Ответ на: комментарий от dissident

Ха! /ge позволяет прямо внутри второго // делать подставления!

Еще раз спасибо, мои волосы теперь вроде бы окончательно шелковисты.

dissident ★★
() автор топика
Ответ на: комментарий от dissident

Просветился окончательно! Можно ситерировать по группам. 
Достаточно было дать в $str =~/.../g. Тогда можно ехать циклом до $#+..

Но я вообще вот так сделал:

$line =~ s/(threadName=\")([a-zA-Z ]*) ([0-9]+)-([0-9]+)(\")/$curr_max = ($3 > $curr_max) ? $3 : $curr_max/ge;

А больше всего меня сразило наповал вот это:

s/(threadName=\")([a-zA-Z ]*) ([0-9]+)-([0-9]+)(\")/$thread_nmbr = $3 + $prev_max_thread_nmbr, "$1 Comp $file_count: $2 $thread_nmbr-$4$5"/ge;

То есть я могу по дороге что-то посчитать и потом подставить. Wow!
Теперь осталось только сделать symlink с sed на perl. ;)

dissident ★★
() автор топика
Ответ на: комментарий от dissident

Вообще можно еще использовать конструкции типа:

while ($str =~ s/PATTERN/REPLACING/e) {

<Анализ>

}

roller ★★★
()
Ответ на: комментарий от roller

Я решил для себя так:

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

С другой стороны SAX parsing в Яве или еще где с этой проблемой бы справился (например если бы там строки содержали множество элементов), но мои три строчки в Perl превратились бы в целый большой класс в Яве например или в где-нибудь еще.

Те файлы с которыми я имел дело в принципе теоретически таких строк что бы убили перла содержать не должны.

Вобщем просто в некоторых случаях наверное нужно просто ставить перед собой реальные задачи.

С другой стороны вопрс применения регэкспов к стриму остается - интересно чисто из любопытства чем это можно сделать (sed и прочие как выясняется помещают строку в память).

dissident ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.