Все задачи

Загадочная таблица

29 Mar 2013

У программиста в файле хранилась таблица:

> cat table.txt
|Alan|blue|168|23
|Brendon|green|178|36
|Carlyle|brown|190|50
|David|brown|180|20

Программисту понадобилось удалить последнюю колонку в этой таблице, и он попробовал сделать это с помощью Perl-однострочника:

> perl -lne '@a = split "|"; pop @a;  print join "|", @a;' table.txt > result.txt

Но…

Подсказка-1

Показать

В новом файле оказалась полная чушь:

> cat result.txt
||A|l|a|n|||b|l|u|e|||1|6|8|||2
||B|r|e|n|d|o|n|||g|r|e|e|n|||1|7|8|||3
||C|a|r|l|y|l|e|||b|r|o|w|n|||1|9|0|||5
||D|a|v|i|d|||b|r|o|w|n|||1|8|0|||2

Подсказка-2

Показать

Функция split в качестве первого параметра принимает не просто строку, но регулярное выражение.

Разоблачение

Показать

Проблема в символе “ ”, по которому программист пытается разбить строку на поля.

Так как первый параметр split’а – регулярное выражение, split '|', $str работает так же, как split m/|/, $str, или split m//, $str, или split '', $str

Ну а split по пустому регулярному выражению разбивает строку на отдельные символы. Так что split "|", "|Alan|blue" дает список ("|", "A", "l", "a", "n", "|", "b", "l", "u", "e"), и потом эти списки символов просто были склеены через “|”.

Хорошим вариантом было бы квотировать спецсимволы:

> perl -lne '@a = split /\|/; pop @a;  print join "|", @a;' table.txt
|Alan|blue|168
|Brendon|green|178
|Carlyle|brown|190
|David|brown|180

Или можно воспользоваться автоматическим разбиением входных строк, которое включается параметром -a (разделитель для split’а указывается ключом -F):

> perl -F'\|' -alne 'pop @F;  print join "|", @F;' table.txt
|Alan|blue|168
|Brendon|green|178
|Carlyle|brown|190
|David|brown|180