Как пропустить строки, которые не являются пробелами или числами в Perl? - PullRequest
1 голос
/ 04 апреля 2009

Я читаю данные из файла, подобного этому

while (<$fh>)
{
        @tmp = split; # <-- ?
        push @AoA, [@tmp];
}

У меня есть пара вопросов по этому поводу. Что делает отмеченная линия? Разбивает ли он файл по строкам и сохраняет элементы каждой строки в массиве? Если это так, возможно ли преобразовать @tmp в строку или сделать регулярное выражение для @tmp?

По сути, я хочу прекратить помещать данные в AoA, если я найду в файле что-то кроме пробела или целого числа. У меня уже есть регулярное выражение: \ ^ [\ s \ d] * $ \

Ответы [ 10 ]

8 голосов
/ 04 апреля 2009

[@tmp = split;] является сокращением для:

@tmp = split " ", $_, 0;

, который похож на

@tmp = split /\s+/, $_, 0;

, но игнорирует все начальные пробелы, поэтому " foo bar baz" становится ("foo", "bar", "baz") вместо ("", "foo", "bar", "baz").

Он берет каждую строку в обработчике файла $fh и разделяет ее, используя пробелы в качестве разделителя.

Что касается того, что вы хотите сделать, почему бы вам просто не запустить регулярное выражение на $_ для начала? Это строка.

Вы можете сделать:

while (<$fh>) {
    last unless  /^[\s\d]*$/; # break if a line containing something 
                              # other than whitespace or a number is found
    @tmp = split;
    push @AoA, [@tmp];
}
5 голосов
/ 04 апреля 2009

Если вам интересно, что делает встроенный в Perl, прочитайте его документацию. Большинство ответов, которые вы получаете, просто восстанавливают документацию. Ключом к использованию любого языка является изучение того, как использовать его документацию. Если вы читали документы и не понимаете этого, укажите это в своем вопросе:)

  • Вы можете просмотреть страницу perlfunc , чтобы увидеть все встроенные модули.

  • В командной строке вы можете использовать ключ -f для perldoc, чтобы получить только документацию для встроенного: perldoc -f split

Удачи,:)

3 голосов
/ 04 апреля 2009
while(<$fh>) {

Это читает файл построчно. Текущая строка файла сохраняется в $_. Это в основном так же, как while($_ = <$fh>) {. Технически он расширяется до while(defined($_ = <$fh>)) {, но они очень близки к одному и тому же (и в любом случае, он автоматический, поэтому вам не нужно об этом беспокоиться).

  @tmp = split; 

"split" без аргументов (в основном) эквивалентно "split /\s+/, $_". Он разбивает текущую строку на список элементов между пробелами. Таким образом, он разбивает текущую строку на список слов (более или менее) и сохраняет этот список в массиве. Однако эта линия плохая. @tmp должен быть квалифицирован как my. Perl поймает это, если у вас есть use strict; и use warnings; наверху.

  push @AoA, [@tmp];
}

Это помещает ссылку на анонимный массив, содержащий элементы, которые были в @tmp, в @AoA, который представляет собой массив массивов (как вы, вероятно, уже знали).

Итак, в конце концов, у вас есть список @AoA, где каждый элемент в списке соответствует строке файла, а каждый элемент списка - это другой список слов в этой строке.

Короче говоря, @tmp должно действительно быть объявлено с использованием my, и вы должны use strict; и use warnings;. На самом деле, как уже было сказано, вы можете покончить с @tmp в целом:

while(<$fh>) { push @AoA, [split] }

Но использование временного массива может быть лучше для тех, кому нужно добавить этот код позже.

РЕДАКТИРОВАТЬ: я пропустил регулярное выражение, которое вы хотели добавить:

while(<$fh>) {
  last unless /^[\d\s]*$/;
  push @AoA, [split];
}

Однако, /^[\d\s]*$/ не поймает все целые числа - в частности, оно не будет соответствовать -1. Если вы хотите, чтобы оно совпадало с отрицательными числами, используйте /^[\d\s-]*$/. Кроме того, если вы хотите сопоставить нецелые числа (числа с плавающей точкой), вы можете использовать /^[\d\s\.-]*$/, но я не знаю, хотите ли вы сопоставить их. Однако эти регулярные выражения будут совпадать с недопустимыми записями, такими как 1-3 и 5.5.5, которые НЕ являются целыми числами или числами. Если вы хотите быть более строгим, попробуйте следующее:

LOOP: while(<$fh>) {
  my @tmp = split;
  for(@tmp) {
    # this line for floating points:
    last LOOP unless /^-?\d+(?:\.\d+|)$/;
    # this line for just integers:
    last LOOP unless /^-?\d+$/;
  }
  push @AoA, [@tmp];
}
3 голосов
/ 04 апреля 2009

[@tmp = split;] разбивает каждую входящую строку файла на пробел и сохраняет слова в виде массива в @tmp. (Цикл while () повторяется по каждой строке в файле.) Ссылка на массив, содержащая @tmp, затем помещается в @ AoA.

Лучший способ выполнить 'преобразование @tmp в строку', если вы хотите что-то с этим сделать прямо сейчас, - это никогда не конвертировать из в строку; split работает на $ _ , которая является строкой (цикл while неявно устанавливает это). Если вы выполняете операции регулярного выражения, такие как s / foo / bar / в этом цикле, они автоматически будут работать с $ _.

Итак, один из способов выполнить то, что вы говорите, что вы хотите (с несколько упрощенным кодом), это:

while(<$fh>) {
    last
        if /[^\s\d]/;
    push @AoA, [split];
}

Если вы действительно хотите преобразовать @tmp в строку, вы можете сделать:

my $tmp = join ' ', @tmp;
2 голосов
/ 04 апреля 2009

На самом деле, строка while (<$fh>) разделяет файл по строкам; каждая итерация цикла будет содержать новую строку в $_.

Отмеченная линия разделяет строку, сохраненную в $_, пробелами. Таким образом, @tmp будет массивом, содержащим все слова в строке: если строка содержит foo bar baz, @tmp будет ('foo', 'bar', 'baz').

Если вы хотите выполнить регулярное выражение в рассматриваемой строке, то вам следует сделать это до того, как разбить строку. Регулярное выражение в perl соответствует $ _ по умолчанию, поэтому строка довольно проста:

while (<$fh>)
{
    last unless /^[\s\d]*$/;
    @tmp = split;
    push @AoA, [@tmp];
}
1 голос
/ 04 апреля 2009

Предупреждение, \d не означает [0-9] в Perl 5.8 и 5.10 (если вы не используете прагму bytes). Это означает любой символ UNICODE , имеющий свойство digit, например MONGOLIAN DIGIT FIVE U + 1815 (& # x1815;), если вы хотите ограничить его только пробелами и цифрами, с которыми вы можете выполнять математику, вы нужно сказать /^[\s0-9]$/.

0 голосов
/ 04 апреля 2009

Основные вопросы уже довольно хорошо рассмотрены, но есть один аспект подвопроса «превращение @tmp обратно в строку», который не был явно упомянут:

$_ и join ' ', @tmp не эквивалентны. $_ будет содержать строку, как было прочитано. join ' ', @tmp будет содержать слова, найденные в строке, соединенные пробелами. Если строка содержит пробелы без пробелов (например, табуляции), слова, разделенные несколькими пробелами, или пробелы в начале, то две версии «полной» строки будут различаться.

0 голосов
/ 04 апреля 2009

хорошо, круто!

стенография многое объясняет.

Так что я могу сделать это ..

while (<$fh>)
{
        if( /^[/s/d]*$/ ){
          //do something
        }else{
          //do something else;
        }

        @tmp = split;
        push @AoA, [@tmp];
}
0 голосов
/ 04 апреля 2009

split берет полученную строку и преобразует ее в массив путем разделения на пробел - поскольку параметр не задан, он разбивает переменную $_ (это дается каждой строке файла в $fh в свою очередь.

Нет необходимости преобразовывать @tmp в строку, поскольку эта строка уже находится в переменной $_.

Чтобы остановить цикл, если вы сопоставляете любой отдельный символ, не являющийся пробелом или цифрой:

last if /[\s\d]/;

Это немного отличается от вашей версии, которая будет соответствовать любой полной строке, состоящей только из непробельных символов и / или не числовых.

0 голосов
/ 04 апреля 2009

Первая строка является циклом while, как и любая другая, но ее «условие» читает строку ввода из дескриптора файла $ fh в переменную по умолчанию $ _. Если чтение успешно (т.е. мы не в конце файла), тело выполняется. По сути, это «для каждой строки в файле $ fh».

Следующая строка разделяет элементы в $ _ (переменная по умолчанию, запомните, поэтому она не учитывается при вызове split) по пробелам (разделитель по умолчанию) и сохраняет результат в @tmp. Последняя строка добавляет ССЫЛКУ на @tmp на @AoA, массив ссылок на массивы.

Итак, что вы хотите сделать, это сказать (в верхней части цикла)

last if $_ =~ <apropriate regex here>;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...