Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > меняем print местами и не работает


Автор: dpush 1.12.2008, 15:30
есть файл, в нем:
1    1    serv1
2    1    serv2
3    1    serv3
4    2    serv4
5    2    serv5
6    3    serv6

написал код, и случайно заметил что:
Код

    while ($line=<FILE>){        
        chomp $line;                
        foreach (split(/[ ]+|\t+/, $line)){                        
            print ":";
            print $_;
        }
        print "\n";
    }

и второй вариант
Код

    while ($line=<FILE>){        
        chomp $line;         
        foreach (split(/[ ]+|\t+/, $line)){                        
            print $_;            
            print ":";
        }
        print "\n";
    }

первый аутпут(все как и хотели):
perl test.pl -f service.txt
:1:1:serv1
:2:1:serv2
:3:1:serv3
:4:2:serv4
:5:2:serv5
:6:3:serv6


второй (ууупс):
perl test.pl -f service.txt
::1:serv1
::1:serv2
::1:serv3
::2:serv4
::2:serv5
::3:serv6


почему от перемены мест принта совершенно неожиданный вывод????

Автор: amg 1.12.2008, 16:01
Вообще-то Ваш код ничего не должен напечатать(за исключением ругани на неоткрытый filehandle FILE при включенных предупреждениях). Но если заменить <FILE> на <>, то все нормально. 

ЗЫ Почему бы не заменить /[ ]+|\t+/ на ' ' или хотя бы на /\s+/
ЗЫЗЫ А опция -f с какой целью?

Автор: dpush 1.12.2008, 16:20
это часть кодаsmile , а не код целиком... весь не интересен, интересен тока это момент.
через -f  я файл передаю...

Автор: amg 1.12.2008, 16:25
Ух, сообразил, как такой эффект мог получиться. Дело в неправильных концах строк: каждая строка кончается на "\r\n" (DOS-формат), а исполнение скрипта, видимо, происходит на *nix (ну или файл был открыт в бинарной моде). Дальше, думаю, понятно: после того как напечаталось serv1, происходит возврат каретки ("\r"), и двоеточие печатается на месте 1-го символа.

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

Добавлено через 2 минуты и 34 секунды
Цитата(dpush @  1.12.2008,  16:20 Найти цитируемый пост)
через -f  я файл передаю.

dpush, опция -f в перле отнюдь не для передачи файла, не используйте ее, если точно не знаете, что она нужна.

Автор: amg 1.12.2008, 16:40
dpush, позволю себе привести немного более краткий, но аналогичный Вашему код:
Код
while (<>) {
   foreach (split){                        
       print $_;
       print ":";
   }
   print "\n";
}

Вызывать 
perl test.pl service.txt

Автор: dpush 1.12.2008, 17:06
спаибо! похоже на правду!

а про -f -а почему нет? я использую Getopt.. ключ -f относится не к perl а к test.pl .... (> ./test.pl -f file.txt)

Добавлено через 1 минуту и 49 секунд
ща подумал, а разве chomp не должен отрезать концы строк?

Добавлено через 11 минут и 48 секунд
хм, помогло вот это:
Код

chomp $line;
chop $line;

криворуко, да?

всегда думал что chomp достаточно...

Добавлено через 12 минут и 55 секунд
chop - не опечатка, действительно есть такая функция)))

Автор: dpush 1.12.2008, 17:32
оказывается - http://www.perlmonks.org/?node_id=549385

спасибо amg Ваша идея с концами строк в разных осах, и есть правильный ответ!

Автор: tolkien 2.12.2008, 01:11
вобще для удаления перехода на новою строку еще используют такой вариант
s/[\r\n]+$//;

Автор: amg 2.12.2008, 07:25
dpush, С -f все нормально, это я не туда посмотрел по невнимательности. Конечно же, у Вас это опция не перла, а скрипта.

chomp $line;
chop $line;

Это неудачное решение. Если файл будет с правильными концами строк, то результат будет неправильным -- chop удалит последний символ строки. Лучше вместо Вашего регулярного выражения для split используйте ' ' (пробел в кавычках), тогда ни chop, ни chomp не нужет будет (хотя chomp и не помешает). К тому же, у Вашего регулярного выражения для split есть еще один недостаток: если в качества разделителя полей окажется комбинация идужих подряд пробелов и табуляторов, то получится неожиданный результат.  

Другое решение -- вместо chomp используйте вариант tolkien: $line =~ s/[\r\n]+$//;

Автор: amg 2.12.2008, 07:53
Цитата(dpush @  1.12.2008,  17:32 Найти цитируемый пост)
оказывается - проблема решена)
Да это и не проблема то вовсе. Только на этом форуме вопрос о неправильных концах строк и как с этим бороться вставал раз этак двести. Кстати, то что предлагают по приведенной Вами ссылке (устанавливать значение $/ = "\r\n") -- тоже не самое хорошее, т.к. не универсальное решение. Сегодня у Вас файл с непривильными концами строк (например, передали его по FTP, забыв включить ascii-моду), а завтра -- с правильными, chomp ничего не удаляет и скрипт начинает глючить. Универсальные решения предложены выше.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)