2015-08-18 1 views
2

У меня проблемы с моим кодом ниже - я пытаюсь выяснить, как открыть все эти текстовые файлы (CSV-файлы что конец в DIS состоит в том, что у всех есть одна строка в них) и получить из них первые два символа (это все числа) и напечатать их в другом файле с тем же именем с суффиксом «.number». Некоторые из этих файлов .DIS не имеют в них ничего, и в этом случае я хочу напечатать «0».Извлечение первых двух символов из файла в perl в другой файл

Наконец, я хотел бы просмотреть каждый оригинальный .DIS-файл и удалить первые 3 символа - я сделал это через bash.

my @DIS = <*.DIS>; 
foreach my $file (@DIS){ 
    my $name = $file; 
    my $output = "$name.number"; 
    open(INHANDLE, "< $file") || die("Could not open file"); 
    while(<INHANDLE>){ 
     open(OUT_FILE,">$output") || die; 
     my $line = $_; 
     chomp ($line); 
     my $string = $line; 
     if ($string eq ""){ 
     print "0";  
     } else { 
     print substr($string,0,2); 
     } 
    } 
    system("sed -i 's/\(.\{3\}\)//' $file"); 
} 

Когда я запускаю этот код, я получаю список номеров объединяются вместе и пустые файлы .DIS.number. Я довольно новичок в Perl, поэтому любая помощь будет оценена!

ответ

0

Я предлагаю вам сделать это как этот

Каждый *.dis файл открывается, и содержимое считывается в $text. Тогда регулярное выражение замещения используется для удаления первые три символа из строки и захватить первые два в $1

Если подмена удалось тогда содержимое $1 записываются в файл число, в противном случае исходный файл пуст (или короче двух символов) и вместо этого записывается ноль. Остальное содержимое $text затем записываются обратно в файл *.dis

use strict; 
use warnings; 
use v5.10.1; 
use autodie; 

for my $dis_file (glob '*.DIS') { 

    my $text = do { 
     open my $fh, '<', $dis_file; 
     <$fh>; 
    }; 

    my $num_file = "$dis_file.number"; 

    open my $dis_fh, '>', $dis_file; 
    open my $num_fh, '>', $num_file; 

    if (defined $text and $text =~ s/^(..).?//) { 
     print $num_fh "$1\n"; 
     print $dis_fh $text; 
    } 
    else { 
     print $num_fh "0\n"; 
     print $dis_fh "-\n"; 
    } 
} 
+0

Спасибо - все файлы теперь отображаются, но я получаю несколько ошибок. num_files, где исходный dis_file ничего не имеет, в них нет «0». Многие из этих файлов имеют тот же номер, что и другой num_file, где исходный dis_file был ненулевым. Я получаю сообщение об ошибке «Использование неинициализированного значения $ text in print at line 20» и «Использование неинициализированного значения $ text в подстановке (s ///) в строке 13.» Я не совсем уверен, как это исправить. Это потому, что некоторые из файлов dis_files не определены? Наконец, есть ли способ распечатать «-» в исходных файлах DIS, если они пусты? Благодаря! – JDY

+0

@ Justin: Извините, я сделал глупую ошибку. Теперь он должен работать лучше – Borodin

+0

Большое спасибо за помощь. Теперь он работает лучше, но я все еще получаю сообщение об ошибке «использование неинициализированного значения $ text в подстановке (s ///) в строке 13.» Кроме того, я изменил 'print $ fh '- \ n"; 'to' print $ fh "0"; '- Мне было интересно, если бы я мог напечатать« - »в оригинальном файле DIS, а не в новом num_file. – JDY

1

Когда я запускаю этот код, я получаю список чисел, объединенных вместе и пустых .DIS.number файлов.

Это из-за этой линии.

print substr($string,0,2); 

print по умолчанию печати на STDOUT (т.е.. Экран). Вы должны дать ему дескриптор файла для печати.

print OUT_FILE substr($string,0,2); 

Они быть сцеплены, потому что print просто печатает то, что вы сказать ему, что не будет ставить новые строки в вас (есть некоторые global variables which can change this, не связывайтесь с ними). Вы должны добавить новую линию самостоятельно.

print OUT_FILE substr($string,0,2), "\n"; 

В заключительной ноте, при работе с файлами в Perl, я предложил бы использовать lexical filehandles, Path::Tiny и autodie. Они избегают большого количества классических проблем, связанных с файлами в Perl.

+0

Спасибо так много - я буду держать это в виду при использовании печати в будущем! – JDY

+0

Последний вопрос: теперь создаются файлы DIS.number, но только тогда, когда файл DIS> 0 КБ (имеет что-то в нем). Следующий код не выводит никакого файла DIS.number с «0» в нем: 'if ($ string eq" ") { print OUT_FILE" 0 "; } ' Любая идея, почему это может быть? Это потому, что нет строки для perl для сравнения пустой строки? – JDY

+0

@ Justin Я подозреваю, что если условие не срабатывает. '$ string' может быть не совсем пустым; он может содержать пробелы, такие как пробелы и символы новой строки. Вам лучше проверить '$ string! ~/\ S /', который проверяет, не содержит ли строка небелых пробелов. Это двойное отрицание и трудно понять, поэтому переверните свое условие: 'if ($ string = ~/\ S /) {напечатать первые два символа} else {print 0}' – Schwern

-1

этот awk-скрипт извлекает первые два символа каждого файла в собственный файл. Пустые файлы должны иметь одну пустую строку на основе спецификации.

awk 'FNR==1{pre=substr($0,1,2);pre=length(pre)==2?pre:0; print pre > FILENAME".number"}' *.DIS 

Это удалит первые 3 символов

cut -c 4- 

Bash цикл будет лучше сделать оба, что мы должны модифицировать скрипт AWK немного

for f in *.DIS; 
do awk 'NR==1{pre=substr($0,1,2);$0=length(pre)==2?pre:0; print}' $f > $f.number; 
cut -c 4- $f > $f.cut; 
done 

Объяснение: проведите все файлы в * .DTS, для первой строки каждого файла, попытайтесь получить первые два символа (1,2) строки ($ 0), назначенные pre. Если длина pre не равна двум (либо строка пуста, либо только 1 символ), установите строку в 0 или используйте pre; напечатать строку, имя выходного файла будет входным файлом, дополненным суффиксом .number. Назначение $ 0 - это трюк, чтобы сэкономить пару нажатий клавиш, поскольку печать без аргументов печатает $ 0, иначе вы можете предоставить аргумент.

В идеале вы должны указать «$ f», так как он может содержать пробел в имени файла ...

+0

Спасибо за объяснение - где бы я точно представил аргумент, если бы я хотел напечатать «0», когда длина (pre)! = 2? Извините за это, я просто очень новичок в bash и не использовал синтаксис. – JDY

+0

тройной оператор присваивает ноль, если длина не равна двум. 'a = p? b: c' эквивалентно' if (p) a = b else a = c'. Вы можете переписать последнюю часть как 'if (length (pre) == 2) print pre else print 0' – karakfa

Смежные вопросы