Как с помощью регулярного выражения можно найти в строке текст, содержащий специальные символы?

Как лучше оптимизировать процесс поиска совпадений между названиями товаров от поставщика и нашими названиями, учитывая, что у товаров поставщика есть названия категорий, которые необходимо удалить? Мой текущий алгоритм выглядит следующим образом: 
1. получаю массив названий товаров с нашего сайта; 
2. получаю массив названий с категориями от поставщика; 
3. в цикле с помощью регулярного выражения ищу совпадения и вывожу товары, которые были найдены.

Я могу выделить вопросы, на которые мне нужны ответы: 
1. Есть ли более эффективный способ решения этой задачи? 
2. В текущем коде присутствуют ли ошибки или недостатки, которые следует исправить? 

Вот пример кода, который я использую для обработки массива от поставщика: 
<pre><code class="php">
// тут разбираем массив от поставщика
foreach($allProductsKlimatprof as $valKlimatprof){
    // это массив с названием товаров с сайта
    foreach($itemProductAll as $itemAll){
        // ищем совпадения, и если находим, то выводим название товара которое совпало
        if (preg_match('/(?&lt;=[\s,.:;"\']|^)' . $itemAll['name'] . '/', $valKlimatprof['NAME'])) {
            echo $itemAll['name'] . ' - Это те товары, которые нашли и отсеяли&lt;br&gt;';
        }
    }
}</code></pre>

Пример вывода от поставщика: 
<pre><code>Сплит-система T18H-ILC/I/TF05P-LC/T18H-ILU/O
Блок внутренний T09H-SnN2/I
Блок наружный T14H-FMA/O
Сплит-система T12H-SLyR2/I/T12H-SLyR2/O
Сплит-система QV-I24FG1/QN-I24UG1
Сплит-система QV-SR18WA/QN-SR18WA
Блок наружный T42H-FMA2/O
Сплит-система LS-HE18TWE2/LU-HE18UWE2
Блок внутренний LS-MHE24KCE2
Сплит-система QV-CA24WA/QN-CA24WA
Сплит-система T24H-SLyW/I/T24H-SLyW/O
Сплит-система T18H-SNE/I/T18H-SNE/O
Сплит-система T24H-SNE/I/T24H-SNE/O</code></pre>

Обратите внимание, что на данный момент удается находить совпадения только для типов, похожих на: 
<pre><code>LS-MHE09KOA2A
LU-4HE28FME2
LU-4HE36FME2</code></pre>
  • 25 октября 2024 г. 11:33
Ответы на вопрос 2
Ваш вопрос касается оптимизации поиска совпадений между товарами, а также использования регулярных выражений для обработки строк. Давайте рассмотрим ваши вопросы по порядку.

### 1. Есть ли более эффективный способ решения этой задачи?

Ваш текущий способ является довольно примитивным. Для оптимизации процесса можно рассмотреть следующие подходы:

1. **Убрать категории**: Сначала удалите категории из имен товаров поставщика, чтобы оставить только сам товар. Вы можете использовать регулярное выражение для удаления определенных подстрок (категорий) из названия товара.

2. **Используйте массивы и `in_array`**: Вместо вложенных циклов вы можете создать ассоциативный массив, где ключами будут названия товаров с вашего сайта, а значениями — нечто вроде `true`. Это обеспечит O(1) для поиска.

3. **Избегайте регулярных выражений для простых совпадений**: Если вы ищете точное совпадение, то регулярные выражения могут быть излишни. Просто используйте обычные строки для случая, если вам нужно точное совпадение с учетом пробелов и специальных символов.

4. **Обработка специальных символов**: Вы можете предварительно обрабатывать строки, заменяя специальные символы, чтобы избежать проблем с регулярками. 

### Пример оптимизированного кода:

Вот пример того, как можно оптимизировать ваш алгоритм:

```php
// Убираем специальные символы и категории, выполняем обработку
function cleanName($name) {
    // Удаляем категории
    $name = preg_replace('/\b(категория1|категория2|категория3)\b/i', '', $name); 
    // Удаляем специальные символы
    $name = preg_replace('/[^\w\s-]/u', '', $name); 
    // Убираем лишние пробелы
    $name = preg_replace('/\s+/', ' ', trim($name));
    return $name;
}

$cleanedItems = [];
foreach($itemProductAll as $itemAll){
    $cleanedItems[$itemAll['name']] = true; // используем ассоциативный массив
}

// Проверяем совпадения
foreach($allProductsKlimatprof as $valKlimatprof) {
    $cleanedName = cleanName($valKlimatprof['NAME']);
    
    foreach($cleanedItems as $itemName => $exists) {
        // Проверяем наличие названия товара в cleanedName
        if (stripos($cleanedName, $itemName) !== false) {
            echo $itemName . ' - Это те товары, которые нашли и отсеяли<br>';
            break; // прерываем внутренний цикл при первом совпадении
        }
    }
}
```

### 2. В текущем коде присутствуют ли ошибки или недостатки, которые следует исправить?

В вашем текущем коде можно отметить несколько недостатков:

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

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

Регулярные выражения тут не нужны.

Предлагаю просто отформатировать ответ от поставщика и вывести пересечения

$items = array_intersect(
    $companyItems, // на сайте
    array_map(
        function (string $item) {
            $parts = explode(' ', $item);
            return end($parts);
        },
        $supplierItems // от поставщика
    ),
);
Проверка

Похожие вопросы