Как заставить работать цикл for так, как мне хотелось бы

Рейтинг: 0Ответов: 1Опубликовано: 02.03.2023

Всем привет.
Имеется следующий код:

/*В данном цикле необходимо переменной $text присвоить значение LIMIT 100 и выполнять его повторно только после того, как массив из данного цикла был обработан следующими foreach циклами. В переменной $text хранится ID поста и сам текст.*/
for ($i = 0; ; $i = $i+100) {
    $text = $this->db->query("SELECT text, id FROM tabler WHERE key = 0 (LIMIT 100, $i)")->getResultArray();
    if (!empty($sql)) {
        break;
    }
}

/*Ниже мы объявляем переменную $tag, далее в цикле подготавливаем каждое ключевое слово к регулярке. После, во вложенном цикле проходимся всеми подготовленными регулярками по тексту новости для выборки всех возможных категорий. Такая реализация используется для того, что бы можно было использовать в БД ключевым словам/тегам * или .+, как пример*/
    $insert = '';
    $tag = $this->db->query("SELECT text, category FROM tags")
    foreach ($tag as $tags) {
        $tags_text = array($tags['text']);
        $depregex = "/" . implode("|", $tags_text ) . "/i";
        foreach ($text as $value) {
            $lowervalue = mb_strtolower($value);
            if (preg_match($depregex, $lowervalue, $matches)) {
                $insert.= "('$tags['category'], $value['id']'),";
            }
            else {
                //отдельный многострочный инсерт для тех новостей, где категория не была обнаружена
            }
        }
    }
    $insert = trim($insert, ',');
    $this->db->query("INSERT INTO tabler (category, id) VALUES $insert ON DUPLICATE KEY UPDATE id = VALUES(id)");

Задумка такова, что я в цикле хотел бы получать по 100 элементов массива из БД (от 0 до 100, от 100 до 200 и т.д.), а дальше проверять через соседний цикл foreach наличие определенных тэгов (второй цикл написан и работает), а в случае, если массив пустой - прерывать работу цикла for.
Текущий цикл for не вложен в соседний цикл foreach, но они оба располагаются в одной функции.

Имею следующий вопрос:

  1. Как правильно реализовать цикл for, что бы он в переменной хранил массив ровно до того момента, пока его не обработает соседний цикл foreach?

Ответы

▲ 0

@sadkin а выборка из таблицы tags это выборка ключевых слов и категорий?

Зачем тогда цикл по ним? У вас их там вроде было штук 40 же? Запихните эту выборку в массив, где ключом будет ключевое слово, а значением - категория. Из ключей сделайте одно регулярное выражение, через |.

Зачем там кстати mb_strtolower? У вас UTF-8? Регулярное выражение вида /.../ui будет искать для юникода независимо от регистра.

Насколько я помню категория определяется по первому найденному ключевому слову?

Пример:

<?php

$kwds = [
    'источник' => 1,
    'PHP' => 2,
    'базка' => 3,
    'слов' => 4
];

$pattern = "/[^\b](" . implode("|", array_keys($kwds)) .")\b/umi";

$text = <<< EOT
видимо я не понимаю источник постов. Если пост вводится / редактируется 
пользователем и сохраняется, 
то у вас явно есть валидация и сохранение и привязку можно делать где-то 
здесь. Собственно ~40 ключевых 
слов вполне в регулярное выражение влезают и анализируются на порядок 
вхождения (ну или не до конца 
понимаю задачу). Если же вы откуда-то парсите / получаете или пакеты уже 
готовых постов, то вы вполне 
можете организовать очередь их обработки. В общем - явно не хватает 
вводных данных для понимания. 
Но в целом, на мой взгляд, базка всегда менее масштабируема, чем PHP- 
приложение 

EOT;

if (preg_match($pattern, $text, $matches)) {
    echo "Найдено ключевое слово ". $matches[1] 
        . ", категория " . $kwds[$matches[1]] . PHP_EOL;
}

Если все же нужно искать все вхождения ключевых слов по порядку и привязывать к нескольким категориям, то:

if (preg_match_all($pattern, $text, $matches)) {
    foreach($matches[1] as $kw) {
        echo "Найдено ключевое слово ". $kw 
            . ", категория " . $kwds[$kw] . PHP_EOL;
    }
}

Исходя из комментария про проблемы с циклом, попробуем так подойти к задаче:

<?php
/*
 * Используем класс PDO для работы с базой
 */

// Коннект к базе, на примере MySQL
$dsn = 'mysql:dbname=<тут название базы>;host=<тут хост>';
$user = '<пользователь БД>';
$password = '<пароль к БД для пользователя>';
$dbh = new PDO($dsn, $user, $password);

// Формируем массив ключевых слов с категориями
$keywords = [];
$sql = "SELECT text, category FROM keywords"; // Запрос к таблице keywords, для получения ключевых слов 
                                              // как text и категорий, как category
if (($rows = $dbh->query($sql)->fetchAll(\PDO::FETCH_ASSOC))) {
    foreach($rows as $row) {
        $keywords[$row['text']] = $row['category'];
    }
}
// Формируем шаблон для регулярного выражения, для поиска первого по порядку точного вхождения ключевого слова целиком 
$pattern = $keywords? "/\b(" . implode("|", array_keys($keywords)) .")\b/umi" : false;


$sql = "SELECT id, text FROM tabler LIMIT %d, 100"; // Шаблон запроса для выборки постов из таблицы tabler(?), 
                                                    // для получения id поста и текста (text). Порциями по 100 постов за раз.
                                                    // функция sprintf(string, ...) выполнит подстановку в шаблон числового 
                                                    // значения $from на позицию %d
$from = 0; // Переменная offset отвечает за сдвиг в запросе

while(($rows = $dbh->query(sprintf($sql, $from))->fetchAll(\PDO::FETCH_ASSOC))) {
    foreach($rows as $post) {
        if ($pattern && preg_match($pattern, $post['text'], $matches)) {
            echo "Пост id " . $post['id'] . " относится к категории " . $keywords[$matches[1]] . " по слову ".$matches[1] . PHP_EOL;
        } else {
            echo "Для поста id " . $post['id'] . " не нашли ключевых слов" . PHP_EOL;
        } 
    }
    $from+=100; // увеличиваем сдвиг для следующей порции чтения постов
}