Модераторы: Aliance, skyboy, MoLeX, ksnk
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Разбивка строки на слова, Все не так просто как кажется сначала 
V
    Опции темы
Vardoulacha
Дата 21.11.2014, 06:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 183
Регистрация: 11.8.2005

Репутация: нет
Всего: 8



Да, я умею разбивать строку на слова используя разделители пробелы, но... вот в чем вся соль

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

слово1 слово2 слово3


но среди тех строк могут попадаться и вот такие
Код

слово сочетание1 слово2 слово3


и даже такие
Код

слово сочетание1 слово2 слово сочетание3


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

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

но этот метод ломается при вот таких строках:

такой
Код

слово сочетание1 слово2 слово3


и такой
Код

слово1 слово2 слово сочетание3


может кто решал такие задачи, хоть направление бы дать

а вот реальные данные
Nokian 185/70 R14 92T HKPL5
Nokian 245/45 R18 100T HKPL 8 Run Flat  XL
Good Year 175/65 R14 82T UG ICE ARCTIC D-STUD
Good Year 205/70 R15 96T UG ICE ARCTIC D-STUD SUV

т.е. нужно парсить вот такие строки

есть правда еще одна идея, парсить по спец знакам "/" "R" "T", затем по словам блоки бить и брать данные из блоков, т.е. если разбить на блоки получится в первом блоке
Nokian 185
Good Year 205

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

или может есть какой способ проще?
PM MAIL   Вверх
Aliance
Дата 21.11.2014, 09:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


I ♥ <script>
****


Профиль
Группа: Модератор
Сообщений: 6418
Регистрация: 2.8.2004
Где: spb

Репутация: 2
Всего: 137



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

Как пример, сначала заводим массив брендов шин:
Код

$tyreBrands = array(
    'Nokian',
    'Good Year',
    'Continental',
    // ...
);


И далее пишем примерно следующую регулярку:
Код

$pattern = '#(' . implode('|', $tyreBrands) . ')\s...........#';
if (preg_match ($pattern , $subject, $matches)) {
    var_dump( $matches );
}


И дальше в регулярку пихать условия все по очереди.

Добавлено через 14 секунд
В итоге получилось что-то типа такого: http://ideone.com/LWXceo

Если кидается ошибка - можно писать в лог и потом эту запись либо вручную, либо подправить регулярку.
PM MAIL WWW ICQ Skype   Вверх
Gold Dragon
Дата 21.11.2014, 09:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Призрачный
****


Профиль
Группа: Экс. модератор
Сообщений: 6753
Регистрация: 1.3.2004
Где: Россия, Тамбов

Репутация: 1
Всего: 71



ничего не понял.

Покажи строку-оригинал и покажи что должно быть на выходе.. Я думаю так проще


--------------------
Нельзя жить в прошлом, оно уже прошло.
Нельзя жить в будущем, оно ещё не наступило.
Нужно жить в настоящем, помня прошлое и думая о будущем!
PM MAIL WWW ICQ   Вверх
Vardoulacha
Дата 21.11.2014, 12:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 183
Регистрация: 11.8.2005

Репутация: нет
Всего: 8



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

Брендов конечно немного, всего 262 )) А вот моделей 5566 ))

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

Gold Dragon, а вот Aliance меня с первого раза понял ))
строки на входе я привел. а на выходе должен получится массив разобранных данных.

Это сообщение отредактировал(а) Vardoulacha - 21.11.2014, 12:07
PM MAIL   Вверх
Gold Dragon
Дата 21.11.2014, 13:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Призрачный
****


Профиль
Группа: Экс. модератор
Сообщений: 6753
Регистрация: 1.3.2004
Где: Россия, Тамбов

Репутация: 1
Всего: 71



Цитата(Vardoulacha @  21.11.2014,  13:04 Найти цитируемый пост)
Gold Dragon, а вот Aliance меня с первого раза понял ))
строки на входе я привел. а на выходе должен получится массив разобранных данных.
Ну массив создать это конечно хорошо, но лучше правило..

Я просто не понял что такое СЛОВО, а что такое СЛОВОСОЧЕТАНИЕ. И вопрос не в делении пробелами, а чем одно отличается от другого..

Вот и хотел увидеть что из этого 
Цитата

Nokian 185/70 R14 92T HKPL5
Nokian 245/45 R18 100T HKPL 8 Run Flat  XL
Good Year 175/65 R14 82T UG ICE ARCTIC D-STUD
Good Year 205/70 R15 96T UG ICE ARCTIC D-STUD SUV
есть СЛОВА

Добавлено через 2 минуты и 54 секунды
ps
кстати, сообщения писали в одно время smile я не видел ответ Aliance


--------------------
Нельзя жить в прошлом, оно уже прошло.
Нельзя жить в будущем, оно ещё не наступило.
Нужно жить в настоящем, помня прошлое и думая о будущем!
PM MAIL WWW ICQ   Вверх
baldina
Дата 21.11.2014, 14:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 4
Всего: 101



судя по примеру напрашивается классификация
<модель> <ширина/высота> <радиус> <нагрузка, скорость> <комментарий>
это можно распарсить регуляркой, например
Код

'|([A-z ]+)\s+(\d+)\/(\d+)\s+R(\d+)\s+(\d+)(\w)\s+(.*)$|'

http://ideone.com/WdhKxv

Это сообщение отредактировал(а) baldina - 21.11.2014, 14:34
PM MAIL   Вверх
Vardoulacha
Дата 25.11.2014, 13:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 183
Регистрация: 11.8.2005

Репутация: нет
Всего: 8



Спасибо всем за помощь, остановился вот на такой строчке

Код

/([A-z ]+)\s(\d{3}).(\d{2})\sR(\d\w+)\s(\d+)([A-zА-я])\s(.+)/


Потом из последнего всего мусора выкидываю лишние спец слова (их немного) и получаю модель

И вот отдав файл парсеру увидел что он запнулся на трех строках
Michelin 235/60 R16 100Т LATITUDE X-ICE NORTH
Michelin 235/60 R17 102Т X-ICE NORTH
Michelin 295/35 R21 107Т X-ICE NORTH

Обычные вроде строки. ничего сложного, но регулярка выдает пустой массив
http://ideone.com/V20Sv7

При этом если эту же регулярку и эти же значения засунуть сюда
http://www.regexr.com/

То там она парсится успешно, понятно что в онлайн не php, а js, но все остальные строки парсятся успешно, а эти вот нет, прям мистика ((
PM MAIL   Вверх
baldina
Дата 25.11.2014, 14:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 4
Всего: 101



у вас в "100Т" T русская. добавьте модификатор 'u' или замените в регулярке \w на .
PM MAIL   Вверх
Vardoulacha
Дата 25.11.2014, 14:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 183
Регистрация: 11.8.2005

Репутация: нет
Всего: 8



baldina, модификатор прокатил, спасибо большое.
PM MAIL   Вверх
Vardoulacha
Дата 16.4.2015, 10:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 183
Регистрация: 11.8.2005

Репутация: нет
Всего: 8



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

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

Итак, предварительная обработка делает из этого

Код

Nokian 185/70 R14 92T HKPL5
Nokian 245/45 R18 100T HKPL 8 Run Flat  XL
Good Year 175/65 R14 82T UG ICE ARCTIC D-STUD
Good Year 205/70 R15 96T UG ICE ARCTIC D-STUD SUV
Michelin 235/60 R16 100Т LATITUDE X-ICE NORTH
Michelin 235/60 R17 102Т X-ICE NORTH
Michelin 295/35 R21 107Т X-ICE NORTH


вот это

Код

Nokian HKPL5
Nokian HKPL 8 Run Flat  XL
Good Year UG ICE ARCTIC D-STUD
Good Year UG ICE ARCTIC D-STUD SUV
Michelin LATITUDE X-ICE NORTH
Michelin X-ICE NORTH
Michelin X-ICE NORTH


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

Строка: Nokian HKPL5
Бренд: Nokian
Модель: HKPL5
Параметры: 

Строка: Nokian HKPL 8 Run Flat  XL
Бренд: Nokian
Модель: HKPL 8
Параметры: Run Flat  XL

так как программа дура, она визуально не может понять что где (привет Искусственный интеллект)

я даже не прошу какое-то готовое решение, мне бы просто понять общий смысл как это выдрать

ах да, есть идеальные базы где перечислены все бренды и все модели, пока придумалось такое решение:
1. Разбиваем строку по пробелам
2. Берем первое слово
3. Ищем среди брендов
4. Если ничего не найдено, значит или это действительно бренд и его нет в базе (но это можно в исключения потом кинуть и руками понять) либо бренд состоит из двух слов
5. Значит берем два слова и снова ищем в брендах (а может быть и 3 и 4 слова)
6. Если прогнав всю строку так и не нашли среди брендов, значит выкидываем строку, пусть программист сам визуально смотрит
7. Если бренд нашли. выкидываем его из начальной строки, сокращая ее и делаем все тоже самое с пункта 2 но уже для моделей
8. Когда найдем модель и выкинем ее из строки там останутся только параметры или пусто

единственное ли это решение, или я мыслю однобоко???

UPDATE
Только написал логику и тут же могу ее сломать, есть модель HKPL 8 и HKPL 8 SUV если будем искать логикой описанной выше, тогда получится следующее
1. Берем два слова HKPL 8
2. Ищем среди моделей и находим, не одну а несколько моделей
3. Значит теперь нам надо из найденных моделей выкинуть ту что искали, чтобы определить все возможные варианты следующего (или нескольких) слов
4. В примере найдем "" и " SUV"
5. Берем третье слово, если оно SUV значит надо брать вариант с SUV, иначе берем вариант без слова SUV

и херак тут же и эту логику можно сломать, а если там слово TL (ну допустим), а у нас еще нет такой модели, тогда мы возьмем модель HKPL 8, что будет неверным, ведь оказывается есть новая модель HKPL 8 TL,  но т.к. в системе нет такого значит это либо новая модель либо это параметр и он правильно отсеялся и модель HKPL 8, чорт (

Это сообщение отредактировал(а) Vardoulacha - 16.4.2015, 10:59
PM MAIL   Вверх
Aliance
Дата 16.4.2015, 15:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


I ♥ <script>
****


Профиль
Группа: Модератор
Сообщений: 6418
Регистрация: 2.8.2004
Где: spb

Репутация: 2
Всего: 137



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

Добавлено через 3 минуты и 8 секунд
Код

$tyreBrands = [
    'Nokian',
    'Good Year',
    'Continental',
    // ...
];

$tyreBrandModels = [
    'Nokian' => [
        'HKPL5',
        'HKPL 8',
        // ...
    ],
    // ...
];

$pattern = '#(' . implode('|', $tyreBrands) . ')#';
if (preg_match ($pattern , $subject, $matches)) {
    var_dump( $matches, $tyreBrandModels[$matches[1]] );
}

PM MAIL WWW ICQ Skype   Вверх
Vardoulacha
Дата 2.5.2015, 08:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 183
Регистрация: 11.8.2005

Репутация: нет
Всего: 8



Aliance, да ваше решение хорошее, но есть одно но, если брендов довольно мало около 500, то моделей ОЧЕНЬ много база содержит уже более 3000 записей, и это только правильные названия моделей, а есть еще алиасы "кривых" названий (это когда вместо Yokohama написано например Yоkohama и только редакторы с подсветкой синтаксиса покажут в чем отличие этих двух строк, во втором слове первая буква "о" русская, даже не спрашивайте как эти криворукие смогли это написать, но это реальный пример). Еще в вашем решение есть один подвох, если бренды оно еще более менее проработает, то вот с такими моделями уже не прокатит: Nokian 275\75 R16 HKPL 8 98T SUV, пример выдуманный (сейчас нет под рукой реального) , но смысл думаю понятен, модель HKPL 8 SUV разбита на две части.

Передумал я еще множество различных вариантов и остановился вот на таком:

1. Берем SQLite
2. Собираем таблицы с помощью команды CREATE VIRTUAL TABLE TableName USING FTS4
http://www.dotnetperls.com/sqlite-fts3
3. Создаются таблицы со всеми записями типа Бренд1 Модель1, Бренд1 МодельАлиас1, Бренд1 МодельАлиас2

Файл с базой получился на 570 мегабайт

Далее выдираем из строки размеры шины (это в принципе сделать легко получилось т.к. там хоть логика есть), а все что остается кроме размеров это бренд и модель которые становятся одной строкой, далее используем запрос в таблицу SELECT data FROM BrandModel WHERE alias MATCH string

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

Мне кажется это лучшее решение )) Пока нашли тут только один минус, это размер базы данных, но согласно спецификации SQLite
Количество таблиц в БД = 2 147 483 646 (у меня всего то 4 таблицы)
Размер БД = 140 терабайт !!! так что тут скорее лимит в размер файла в файловой системе, не помню точно какая файловая система на сервер и какой размер блока, но даже если это ext3 и размер блока 1 кб то это максималка 16 гигабайт, что тоже кажется слишком избыточным

Цитата

Pages are numbered beginning with 1. The maximum page number is 2147483646 (231 - 2). The minimum size SQLite database is a single 512-byte page. The maximum size database would be 2147483646 pages at 65536 bytes per page or 140,737,488,224,256 bytes (about 140 terabytes). Usually SQLite will hit the maximum file size limit of the underlying filesystem or disk hardware size limit long before it hits its own internal size limit.

PM MAIL   Вверх
Aliance
Дата 6.5.2015, 14:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


I ♥ <script>
****


Профиль
Группа: Модератор
Сообщений: 6418
Регистрация: 2.8.2004
Где: spb

Репутация: 2
Всего: 137



А кривые алиасы поступают вам на вход или хранятся в вашей базе? Если второе - то не проще ли написать скрипт, который заменяет кривизну в моделях и периодически его запускать?
PM MAIL WWW ICQ Skype   Вверх
Vardoulacha
Дата 21.5.2015, 05:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 183
Регистрация: 11.8.2005

Репутация: нет
Всего: 8



В том то и соль, что кривые алиасы поступают извне и заранее неизвестны.

База sqlite разрослась до 3.8 гб )) Посматриваем в сторону MongoDB
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Тексты | Следующая тема »


 




[ Время генерации скрипта: 0.2040 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.