regex help - игнорировать символ, если он в кавычках
У нас есть веб-приложение, где вы можете ввести регулярное выражение в поле поиска, и оно возвращает совпадения из базы данных.
Вот пример того, как могут выглядеть записи базы данных. Они разделены запятыми (представьте, что каждая запись - это семья - каждая семья может содержать от 1 до n записей):
record1: "john doe"<john@email.com>;male,"jane doe"<jane@email.com;female
record2: "john smith"<jsmith@email.com>
record3: "smith, jane"<jane@smith.com>
Что мне нужно сделать, это ввести регулярное выражение, поэтому я получаю только первую запись. В рабочем сценарии выводом будет все, вплоть до разделителя:
record1: "john doe"<john@email.com>;male
record2: "john smith"<jsmith@email.com>
record3: "smith, jane"<jane@smith.com>
На самом деле, все мои попытки видеть запятую в "кузнец, джейн" как разделитель.
Как игнорировать запятую, если она в кавычках? (Для проверки на будущее, способность игнорировать запятые в одинарных кавычках тоже будет хорошей)
Я могу использовать только регулярные выражения, а не awk/sed и т. Д., А разновидность регулярных выражений - POSIX Extended.
4 ответа
Подчеркните: вам нужно детализировать вашу среду немного больше, как указано в комментариях.
Вот одна попытка моей оболочки Unix с sed
Да я знаю ты не хочешь sed
, но это может помочь вам построить регулярное выражение в вашей среде.
data.txt:
"john doe"<john@email.com>;male,"jane doe"<jane@email.com;female
john_doe"<john@email.com>;male,"jane doe"<jane@email.com;female
# sed -n 's|^\("[^"]\+"[^,]\+\).*|\1| p' data.txt
"john doe"<john@email.com>;male
Идея регулярного выражения заключается в том, чтобы перепрыгнуть через первую пару двойных кавычек, а затем искать запятую.
Это не удастся, если нет двойных кавычек.
Его можно масштабировать для использования одинарных кавычек.
Обновление:
Ищите @
с последующим ,
...
data.txt:
"john doe"<john@email.com>;male,"jane doe"<jane@email.com;female
john_doe"<john@email.com>;male,"jane doe"<jane@email.com;female
# sed -n 's|\([^@]\+[^,]\+\),.*|\1| p' data.txt
"john doe"<john@email.com>;male
john_doe<john@email.com>;male
Теперь вы получаете оба случая, а затем также те без названия строки или даже <>
заворачивать.
Но ваша проблема в зависимости от ,
- перерывы для record2 и record3, где у вас есть один адрес электронной почты и без запятой. Все равно будет работать, если вы заставили ,
в конце каждой записи.
Вы не можете надежно сделать это с помощью регулярных выражений. Лучшее, что вы сможете сделать, это уродливый хак, основанный на куче предположений, которые гарантированно сломаются в конце концов, если вы решитесь внедрить такой код в производство. (Если вы не можете сделать это с огневой мощью полностью вооруженного и работающего движка регулярных выражений Perl, то вы, конечно, не сможете сделать это с расширенными регулярными выражениями POSIX.)
Короче говоря, чтобы надежно решить эту проблему, вам нужно будет найти какой-то способ расширить любой код, с которым вы работаете, чтобы он мог использовать библиотеку синтаксического анализа CSV, или в случае ее сбоя вам придется написать парсер
Конечно, если вы не можете изменить код, который обрабатывает файлы, о которых идет речь, то вы застряли с отвратительными взломами, что в этом случае вызывает сожаление, так как я не вижу действительно надежного способа получения желаемого результата с регулярными выражениями POSIX в качестве единственного инструмента.
Используйте regex, чтобы изменить разделитель, если он заключен в кавычки с чем-то вроде tab:
Шаблон ((?:[^,"]|"[^"]*")+),
Заменить \1\ т
Затем разделить на новый разделитель
Попытка игнорировать запятую внутри кавычек проблематична, потому что запятая, которую вы хотите найти, также находится в кавычках (конечная кавычка "john doe"
и открытая цитата "jane doe"
). Если вы не предполагаете, что первая цитата существует, вам будет трудно сделать это различие.
Попробуйте это вместо:
^[^<]+<[^>]*>[^,\s]*
Я предполагаю, что каждая запись будет иметь <email>
и любая запятая после электронного письма будет указывать новую запись. Это просто обменяет одно предположение на другое, но в моем тесте это сработало.