Как узнать, является ли файл языком табуляции или пробелами в Perl? - PullRequest
2 голосов
/ 31 марта 2009

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

Я думал о том, чтобы прочитать каждый символ файла и проверить, является ли оно целым числом. Если не получится, я покажу выходное сообщение. Есть ли лучший способ сделать это?

Я проверил несколько примеров и могу прочитать весь файл построчно, но как я могу прочитать каждый символ в этой строке? Должен ли я делиться на space или tab, так как файл может быть либо?

Ответы [ 7 ]

8 голосов
/ 31 марта 2009

Достаточно легко разделить на и пробелы и табуляции:

my @fields = split /[ \t]/, $line;

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

Проверка целочисленных значений проста:

for my $val ( @fields ) {
    die "'$val' is not an integer!" if $val !~ /^-?\d+$/;
}
3 голосов
/ 31 марта 2009

звучит так, как будто это не имеет значения, если оно разделено пробелами или табуляцией В какой-то момент вам придется прочитать все символы файла, чтобы проверить их и проанализировать. Зачем делать эти два шага. Потребляйте целые числа из файла, пока не столкнетесь с чем-то, что не является пробелом или допустимым целым числом, а затем пожалуетесь (и, возможно, откатитесь)

1 голос
/ 31 марта 2009

Я загружаю файл в Perl Программа из HTML-страницы. После файл был загружен, я хочу определить, является ли файл (пробел или табуляция) и все значения являются целыми числами. Если это не случай, то я хочу вывести некоторые сообщение.

Это условие означает, что ваши данные должны содержать только цифры, пробел и символы табуляции (в основном это должны быть цифры и пробел или только цифры и табуляция).

Для этого просто загрузите данные в переменную и проверьте, совпадают ли они:

$data =~ /\A[0-9 \t]+\z/;

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

Если ваш следующий шаг - извлечь эти целые числа (что звучит логично), вы можете легко это сделать:

@integers = split /[ \t]+/, $data;

или

@integers = $data =~ /(\d+)/g;
0 голосов
/ 31 марта 2009

Чтобы добавить к ответу, я напишу ясный и простой. Эта версия:

  1. использует только самые основные функции и конструкции Perl, поэтому любой, кто знает хотя бы маленький Perl, должен получить его довольно быстро. Не оскорблять или что-то в этом роде, и не стыдно быть новичком - я просто пытаюсь написать что-то, что вы сможете понять, независимо от того, какой у вас уровень мастерства.
  2. принимает символы табуляции или пробелы в качестве разделителя, что позволяет свободно смешивать их. В закомментированном коде будет подробно описан тривиальный способ применения одного или во всем документе.
  3. выводит хорошие сообщения об ошибках, когда они содержат неверные значения. Должен показать недопустимое значение и строку, в которой оно появилось.
  4. позволяет обрабатывать данные так, как вам нравится. Я не собираюсь хранить его в массиве или чем-то еще, просто поместите ... в одну точку, и там вы добавите немного кода, чтобы выполнить любую обработку данных в данной строке, которую вы хотите выполнить.

Итак, вот так:

use strict;
use warnings;

open(my $data, "<", $filename);
# define $filename before this, or get it from the user

my $whitespace = "\t ";

chomp(my @data = <$data>);

# check first line for whitespace to enforce...
#if($data[0] =~ /\t/ and $data[0] !~ / /) {
#  $whitespace = "\t";
#} elsif($data[0] =~ / / and $data[0] !~ /\t/) {
#  $whitespace = " ";
#} else {
#  warn "Warning: mixed whitespace on line 1 - ignoring whitespace.\n";
#}

foreach my $n (0 .. $#data) {
  my @fields = split(/[$whitespace]+/, $data[$n]);
  foreach my $f (@fields) {
    if($f !~ /-?\d/) { # \D will call "-12" invalid
      if($f =~ /\s/) {
        warn "Warning: invalid whitespace use at line $n - ignoring.\n";
      } else {
        warn "Warning: invalid value '$f' at line $n - ignoring.\n";
      }
    } else {
      ... # do something with $f, or...
    }
  }
  ... # do something with @fields if you want to process the whole list
}

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

РЕДАКТИРОВАТЬ: исправлено мое регулярное выражение для сопоставления целых чисел. Раньше он был ленивым и допускал «12-4», что, очевидно, не является целым числом (хотя оно оценивается как единое целое - но это гораздо сложнее (ну, не совсем, но это не то, что хочет ОП (или так?) было бы забавной особенностью (ВСТАВЬТЕ ШУТ LISP ЗДЕСЬ)))). Спасибо, Висний. Я рад, что перечитал твой пост, так как ты написал лучшее выражение, чем я.

0 голосов
/ 31 марта 2009

Я предполагаю несколько вещей о вашем формате и желаемых результатах.

  • последовательных коллапса.
  • числа могут не переноситься вокруг строк, т. Е. Новые строки фактически являются разделителями.
  • Вкладки и пробелы в одном файле в порядке. Любой разделитель является приемлемым.
  • файлов достаточно малы, поэтому обработка всего файла не будет проблемой.

Кроме того, мой код принимает любые пробелы в качестве разделителя.

use strict;
use warnings;

# Slurp whole file into a scalar.
my $file_contents;
{   local $/;
    $/ = undef;
    $file_contents = <DATA>;
}

# Extract and validate numbers
my @ints = grep validate_integer($_), 
                split( /\s+/, $file_contents ); 
print "@ints\n";


sub validate_integer {
    my $value = shift;

    # is it an integer?
    # add additional validation here.
    if( $value =~ /^-?\d+$/ ) {
        return 1;
    }

    # die here if you want a fatal exception.
    warn "Illegal value '$value'\n";
    return;
}

__DATA__
1 -2 3 4
5 8.8
-6
    10a b c10 -99-
    8   9 98- 9-8
10 -11  12  13

В результате:

Illegal value '8.8'
Illegal value '10a'
Illegal value 'b'
Illegal value 'c10'
Illegal value '-99-'
Illegal value '98-'
Illegal value '9-8'
1 -2 3 4 5 -6 8 9 10 -11 12 13

Обновления:

  • Исправлена ​​обработка отрицательных чисел.
  • Заменена проверка map на grep.
  • Переключен на split вместо захвата без пробелов из re.

Если вы хотите обрабатывать файл построчно, вы можете заключить grep в цикл, который читает файл.

0 голосов
/ 31 марта 2009

Ваш вопрос не очень понятен. Похоже, вы ожидаете, что данные будут в этом формате:

123 456 789
234 567 890

Другими словами, каждая строка содержит одну или несколько групп цифр, разделенных пробелом. Предполагая, что вы обрабатываете файл по одной строке за раз, как вы сказали в исходном вопросе, я бы использовал это регулярное выражение:

/^\d+(\s+\d+)*$/

Если могут быть отрицательные числа, используйте вместо этого:

/^-?\d+(\s+-?\d+)*$/

Ваше регулярное выражение не будет соответствовать пустой строке, и эта также не будет. Вероятно, так и должно быть; Я ожидал бы, что пустые строки (включая строки, содержащие только пробелы) будут запрещены в таком случае, как это. Однако в конце файла может быть одна или несколько пустых строк. Это означает, что как только вы найдете строку, которая не соответствует приведенному выше регулярному выражению, вы должны убедиться, что каждая из оставшихся строк имеет нулевую длину.

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

0 голосов
/ 31 марта 2009

Вы можете просто использовать регулярное выражение. Это то, чем славится Perl; -).

Простой пример:

perl -ne 'if ($_=~/^(\d+\s+)+$/){print "yep\n";}'

будет принимать только те строки, которые содержат только цифры и пробелы. Это должно помочь вам.

...