![]() |
Задавайте вопросы, мы ответим
Вы не зашли.
Ребята, привет всем!
Помогите советом или идеей в следующей ситуации. Есть необходимость разбить входную строку на отдельные слова. Отдельными словами в первую очередь считаются части строки, разделенные запятыми, но также внутри этих подстрок отдельными словами считаются специальные символы и прочие не буквенные знаки. Таким образом, входная строка "qwe 123 @ abc$" должна быть разбита на слова:
1. "qwe"
2. " "
3. "1"
4. "2"
5. "3"
6. " "
7. "@"
8. " "
9. "abc"
10. "$"
Не вдаваясь в подробности реализации, я выполнил логику (анализ строки на предмет буквенных знаков) с использованием MySQL оператора REGEXP. А конкретнее с помощью класса символов (character class) alpha - alphabetic characters:
Отредактированно FiMko (02.03.2012 09:27:26)
Неактивен
Вы все реализуете на языке SQL? Для такой задачи проще не использовать regexp, а посимвольно пройти строку - в этом случае задача решается за один проход.
Неактивен
Спасибо за помощь!
rgbeast написал:
Вы все реализуете на языке SQL?
Да. Подпрограмма анализа строк загоняет результаты работы во временную таблицу, вызывающая главная процедура затем работает с этими данными. Сама подпрограмма разбора строк на самом деле несложна, порядка 20-ти строк.
Согласен, не классический способ выполнять такого рода вычисления на стороне базы данных. Но что делать. Если я вынесу эту логику в PHP, обработаю строки и вставлю их, скажем, не во временную таблицу, а в постоянную и затем главная процедура будет основывать свою работу на "знании", что данные готовы и уже в таблице, то [1] такое "знание" сильно ухудшает инкапсуляцию компонентов системы (PHP - База данных) [2] если что-то пойдет не так при работе с данными в главной процедуре в MySQL, не возможно использовать транзакции для отмены изменений, внесенных PHP.
rgbeast написал:
Для такой задачи проще не использовать regexp, а посимвольно пройти строку - в этом случае задача решается за один проход.
Если посимвольно, то как будет выглядеть проверка "текущий символ - это буквенных знак?" ([[:alpha:]] для регулярных выражений). Плюс посимвольно - это не один проход, для строки из 1000 символов (максимальная длина) - 1000 проходов.
Отредактированно FiMko (02.03.2012 11:07:28)
Неактивен
SQL это слишком высокоуровневый язык, отсюда и REGEXP. На SQL не знаю хорошего решения. Посимвольная работа не будет быстрой, так как потребует сначала разбивать функцией substring на символы, а потом проверять опять же regexp-ом. Под одним проходом я имел в виду, что можно в одном цикле обойти все символы и проверить на буквенность, но это не решение для SQL.
Неактивен
rgbeast написал:
SQL это слишком высокоуровневый язык, отсюда и REGEXP. На SQL не знаю хорошего решения. Посимвольная работа не будет быстрой, так как потребует сначала разбивать функцией substring на символы, а потом проверять опять же regexp-ом. Под одним проходом я имел в виду, что можно в одном цикле обойти все символы и проверить на буквенность, но это не решение для SQL.
Безусловно, здесь необходим какой-то компромисс в архитектуре. По факту данная задача с точки зрения разработки программы решается и в SQL весьма примитивными манипуляциями. Проблема в производительности.
Мне сложно делать в данной ситуации ставки на лучшую производительность в PHP, ибо ему (PHP) придется также взаимодействовать с базой для вставки полученных после разбиения слов. Конечно, можно вставить все разом, но остается проблема с возможным последующим rollback. И пр. и пр.
Компромисс, который я вижу сейчас: не бояться иметь в базе для строки "abc abc! abc?" дупликаты слов вида: "abc", "abc!", "abc?" и т.д. Разбиение же входной строки на слова на основе разделителя пробел работает довольно шустро. Здесь я жертвую результатами поиска, то есть, скажем для запроса "abc" будет найден только "abc", но не "abc!" или "abc?". Использовать "LIKE %abc%" не хочу из соображений производительности.
В общем задача сильно индивидуальная. rgbeast, спасибо Вам, что не оставили ее без внимания. Я думаю...
Отредактированно FiMko (02.03.2012 16:49:33)
Неактивен
FiMko написал:
Я думаю...
Следующим шагом начал городить огород с построением собственного словаря с позициями знаков препинания внутри исходной строки и последующим ее (строки) разбиением на слова на основе этого словаря. Используя полученный словарь позиций, стало возможно реализовать всё без регулярных выражений, прирост скорости получился весьма незначительным. В итоге придумал некое компромиссное решение.
Отредактированно FiMko (05.03.2012 10:39:45)
Неактивен
А если в in_string накопить в таком формате :
Отредактированно evgeny (04.03.2012 22:27:30)
Неактивен
evgeny написал:
А если в in_string накопить в таком формате :
select (@a:=1) `id`,'qwe' `word`
union all
select (@a:=@a+1) `id`,'#' `word`
union all
select (@a:=@a+1) `id`,'#' `word`
union all
...
то можно и без временной таблицы.
evgeny, спасибо за ответ! Да, можно и не во временную таблицу, а в строку, вариантов много. Мне нужно именно во временную таблицу, потому что работать с этими данными предстоит главной, вызывающей процедуре, иначе в ней придется еще строку разбирать.
Неактивен