PHP-скрипт для захвата всей строки

Спасибо, что нашли время, чтобы прочитать это, и я буду признателен за каждый ответ, независимо от качества содержания. :)

Я пытаюсь создать php-скрипт, который ищет в текстовом файле определенный текст. Человек вводит определенный текст в форме HTML, и скрипт php должен искать этот конкретный текст в текстовом файле.

Значением поля ввода HTML-формы является имя пользователя, а в документе php переменная $ username представляет собой введенные данные, пример показан ниже:

$username = $_POST['username'];

Текстовый файл ниже называется begin.txt:

АУЛЛАХ1 01.07.2010 15:28 55621454 123456 123456.00

ИМЯ ПОЛЬЗОВАТЕЛЯ 03.07.2010 18:21 55621454 123456 123456.00

АУЛЛАХ1 07.07.2010 15:05 55621454 189450 123456.00

SUPREMEGAMER 8.07.2010 18:42 55621454 123456 123456.00

Если человек вводит HTML-форму AULLAH1, я бы хотел, чтобы скрипт php захватил последнюю запись AULLAH1 в текстовом файле (например, он должен захватить третью строку, а не первую, поскольку третья строка является последней записью, содержащей текст АУЛЛАХ1). Кроме того, когда человек вводит определенный текст, он не должен просто захватывать документ или текст, он должен захватить всю строку: AULLAH1 07/07/2010 15:05 55621454 189450 123456.00 и поместить ее в php переменная, может что-то вроде $ grabbed? Если вообще возможно.

Любая помощь приветствуется, и я с нетерпением жду ваших ответов; Спасибо. :) Если я ничего не объяснил внятно и / или вы хотите, чтобы я объяснил более подробно, пожалуйста, ответьте. :)

Спасибо.


person aullah    schedule 21.08.2010    source источник


Ответы (5)


Вы можете использовать SplFileObject и перебирать файл построчно.

Обратите внимание, что итерация по файлу намного эффективнее с точки зрения памяти, чем использование file() или file_get_contents(), потому что оно не считывает все содержимое файла в массив или переменную.

$username = 'AULLAH1';
$file = new SplFileObject("data.csv");
$grabbed = FALSE;
while (!$file->eof()) {
     $data = $file->fgetcsv(' ');
     if($data[0] === $username) {
         $grabbed = $file->current();
     }
}
echo $grabbed;

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


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

$username = 'AULLAH1';
$file = new SplFileObject("data.txt");
$grabbed = FALSE;
foreach($file as $line) {
    if(strpos($line, $username) !== FALSE) {
        $grabbed = $line;
    }
}
echo $grabbed;

Если вы хотите убедиться, что $ username было найдено в позиции 1, измените условие if на проверку === 1.


Если по какой-то причине вы хотите иметь все строки, в которых встречается имя пользователя, вы можете написать собственный FilterIterator для перебора содержимого файла, например

class UsernameFilter extends FilterIterator
{
    protected $_username;
    public function __construct(Iterator $iterator, $username)
    {
        $this->_username = $username;
        parent::__construct($iterator);
    }
    public function accept()
    {
        return strpos($this->current(), $this->_username) !== FALSE;
    }
}

Тогда вы можете просто использовать foreach. FilterIterator передает каждую строку accept(), и фактически используются только те строки, для которых он возвращает TRUE.

$filteredLines = new UsernameFilter(new SplFileObject('data.txt'), 'AULLAH1');
foreach($filteredLines as $line) {
    echo $line;
}

Вышеупомянутое выведет

"AULLAH1" "01/07/2010 15:28 " "55621454" "123456" "123456.00"
"AULLAH1" "07/07/2010 15:05 " "55621454" "189450" "123456.00"

Если вы хотите, чтобы эти строки были в массиве, вы можете сделать

$lines = iterator_to_array($filteredLines);

и посмотреть на последний пункт

echo end($lines);
person Gordon    schedule 21.08.2010
comment
Привет, Гордон, спасибо за ответ, я очень признателен. Первый код, который вы предоставили, помог мне, и он работает более чем безупречно. Я просто не могу отблагодарить вас за ваши усилия. ;) Спасибо. - person aullah; 22.08.2010

я бы не использовал текстовый файл для хранения учетных данных, но если вы должны хотя бы изменить формат текстового файла на макет CSV

есть это как это

AULLAH1,01/07/2010 15:28,55621454,123456,123456.00
USERNAME,7/3/2010 6:21 PM,55621454,123456,123456.00
AULLAH1" "07/07/2010 15:05 " "55621454" "189450" "123456.00
SUPREMEGAMER,7/8/2010 6:42 PM,55621454,123456,123456.00

прочтите строку файла мою строку в PHP

<?php
$lines = file('begin.txt');
foreach($lines as $line)
{
     if(preg_match('/(?<username>.*?),(?<ts>.*?),(?<id_1>.*?),(?<id_2>.*?),(?<balance>.*?)/',$line,$parts))
     {
         if($_POST['username'] == $parts['username'])
         {
             //Do what you need here.
             break;
         }
     }
}
?>

вы также можете использовать Explode, ведьма быстрее, но ограничена автоматической генерацией ключей для массива!

<?php
$lines = file('begin.txt');
foreach($lines as $line)
{
    $parts = explode(',',$line);
     if($_POST['username'] == $parts[0])
     {
         //Do what you need here.
         break;
     }
}
?>
person RobertPitt    schedule 21.08.2010
comment
Вы также можете использовать функцию fgetcsv(), которая обрабатывает разделители и escape-символы за вас и возвращает каждую строку в виде массива. - person Lèse majesté; 22.08.2010
comment
Привет, Роберт, спасибо за ответ, я очень признателен. К сожалению, я не могу изменить формат текстового документа на csv, так как на данный момент текстовый документ специально закодирован для динамического ввода данных. Не волнуйтесь, данные не слишком важны. ;) Опять же, я ценю ваш ответ и все ваши старания. ;) - person aullah; 22.08.2010
comment
проблема в том, что если вы взорветесь пробелами, если в кавычках есть пробел, такой как "USER NAME" "1245345", он вернет 3 значения _2 _, _ 3 _, _ 4_ вот так, поэтому witc лучше всего иметь некоторый характер, который не будет использоваться так часто, как pipe _5 _... лучше всего использовать функцию preg_match и сопоставить строки внутри кавычек и разделить пробелами ВНЕ кавычек. - person RobertPitt; 22.08.2010
comment
Regex не работает. preg_match() возвращает количество совпадений с шаблоном. $parts будет целым числом. - person Gordon; 22.08.2010

Использование preg_match_all() может быть решением:

$file = file_get_contents($filename);
$username = 'ALLUAH1';
preg_match_all('/^"'.preg_quote($username, '/').'".*$/m', $file, $matches);
  // Note that the '/m' flag of the regex makes '^' and '$' match
  // the beginning and end of each line.
  // Also note that I am using preg_quote() to escape special regex characters

$grabbed = array_pop($matches[0]);

Теперь $grabbed должен содержать значение последней строки этого пользователя.

Ссылки по теме:

person Frxstrem    schedule 21.08.2010
comment
Привет, Frxstrem, спасибо за ваш ответ, я очень признателен. К сожалению, после добавления строки echo $ grabbed данные не отображаются. Скорее всего, это будет проблемой с моей стороны, а не с вашей. Опять же, я ценю ответ, и я чрезвычайно благодарен за то, что вы ответили. ;) Спасибо. - person aullah; 22.08.2010
comment
@ Aullah1 @Frxstrem неправильно написал $username. Если вы измените его на AULLAH1, он работает. - person Gordon; 22.08.2010

Это самое короткое, что я могу придумать:

$list = file_get_contents('data.txt');
echo strstr(substr($list, strrpos($list, 'AULLAH1')-1), PHP_EOL, TRUE);

Это прочитает файл в память. Затем он находит смещение последнего появления строки 'AULLAH1'. Будет возвращено все, что было за одну букву до этого появления до следующего символа новой строки.

Для этого требуется PHP5.3 из-за третьего аргумента strstr() и требует больше памяти, чем итератор выше. В зависимости от ваших символов новой строки вам может потребоваться изменить PHP_EOL на символы новой строки, используемые в файле.

person Gordon    schedule 21.08.2010
comment
Привет, Гордон, это определенно короткое кодирование, и оно очень эффективно. Хотя в настоящее время у меня нет сервера с PHP5.3. Тем не менее, я в любом случае ценю ваши усилия. Вы очень помогли, и я благодарен за ваш ответ. ;) Спасибо. - person aullah; 22.08.2010
comment
@AUllah спасибо. ИМО, по скорости вышеупомянутое должно быть быстрее, чем любой из других вариантов, которые полностью читаются в файле. Самая быстрая и эффективная память должна быть SplFileObject с strpos. - person Gordon; 22.08.2010

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

$username = "AULLAH1";
$input_file = file("begin.txt");

$grabbed = "";

for($i = count($input_file) - 1; $i >= 0; $i--)
{
  // Note: Exactly zero (string starts the line), NOT "FALSE"
  if(strpos($input_file[$i], "\"$username\"") === 0)
  {
    $grabbed = $input_file[$i];
    break;
  }
}
person sargant    schedule 21.08.2010
comment
Привет, саргант, у вас потрясающий код, и мне нравится, как он читает данные. Одна вещь, однако, похоже, что он не отображает данные после того, как кодировка была введена в документ php. Конечно, это, скорее всего, проблема с моей стороны, а не с вашей. Я очень ценю ваш ответ, а также приложенные вами усилия. Спасибо. ;) - person aullah; 22.08.2010
comment
В коде есть синтаксическая ошибка. Вам необходимо удалить вторую круглую скобку перед === в блоке if. - person Gordon; 22.08.2010