Регулярное выражение для совпадения с открывающей двойной кавычкой, пропускающей двойную кавычку

573
Rhythem Aggarwal

У меня есть большой (25 миллионов строк) файл данных с |разделителем трубы ( ). Поставщик данных предоставляет файлы, и я запускаю автоматизированные задания, чтобы загрузить файлы в базу данных Redshift и затем обработать данные.

Ниже приведен пример данных:

123|110092|ACCT|"HC Account"|"Account1||||||||||||"Mary"|||"|"||||132|"STE|504"|1253|Unspecified Account|||N||ACTV|Active||||04/30/2013|12/31/2099||||||||||||| 

Есть три набора полевых данных, которые я видел до:

  1. Текстовое поле заключено в двойные кавычки ( ") Например: "HC Account", "Mary"и "|". Это правильно, и данные должны быть загружены без кавычек.
  2. Некоторые значения будут содержать разделитель канала. Например: "STE|504". В этом случае поле обязательно должно быть заключено в двойные кавычки. Если это не так, он попадает в категорию три ниже.
  3. Иногда предоставляется только начальная цитата, а конечная цитата отсутствует. Например: "Account1.

TL; DR: любое поле, начинающееся с |", должно заканчиваться на "|. Если это не так, и |"встречается другое, первая двойная кавычка должна быть экранирована.

Итак, моя строка данных должна быть отредактирована, чтобы она стала следующей после предварительной обработки в Unix / Python / другие предложения:

123|110092|ACCT|"HC Account"|"Account1||||||||||||"Mary"|||"|"||||132|"STE|504"|1253|Unspecified Account|||N||ACTV|Active||||04/30/2013|12/31/2099||||||||||||| 


Я планирую написать сценарий Unix для изменения файла с помощью SED. Регулярное выражение, которое я написал до сих пор:

(\|")(?!([a-zA-Z0-9]|\s|\||\/)*("\|)) 

Однако это не соответствует строке правильно.

Вот ссылка на то, где я тестирую это: https://regexr.com/3toib

Я хочу, чтобы код был легковесным, поскольку средний размер файла составляет 3-5 ГБ, а таких файлов обычно несколько (более 10).

PS Redshift - это служба баз данных AWS, использующая Postgre SQL Engine, которая способна удалять кавычки из полей в правильных кавычках и экранировать специальное значение кавычки с помощью \.

Кроме того, я готов сделать это на Python / любом другом языке сценариев, учитывая, что код имеет небольшой вес.

0
Как вы знаете, если "|" труба внутри кавычек, или в двух начальных кавычках отсутствуют их конечные кавычки? djsmiley2k 5 лет назад 1
в этом случае поле похоже на дерьмо `|" | "|`. Так что | "и" | сэндвич трубы внутри для поля. Но я понимаю вашу точку зрения, с более случайными данными это может стать более сложным. Rhythem Aggarwal 5 лет назад 0

1 ответ на вопрос

1
robinCTS

Существует одна ОГРОМНАЯ проблема со спецификациями, которые вы дали для данных. Если "|"допустимая строка или, точнее, строка в кавычках может начинаться с канала, то если строка с отсутствующей конечной кавычкой, например "Account1, имеет в качестве первого следующего поля в кавычках поле, начинающееся с канала, например "|Mary", тогда нет никакого способа определить, во всех случаях, если "|это конец цитаты для |"Account1||||||||||||"|или начало котировка |"|Mary"|.

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

123|110092|ACCT|"HC Account"|"Account1||||||||||||"|Mary|||"|||||132|"|STE|504|1253

видно, что это будет неверно истолковано как

123 110092 ACCT "HC Account" "Account1||||||||||||" Mary   "|||||132|" STE 504 1253

Обратите внимание, что это проблема, используя ли регулярные выражения, Python или любой другой язык. Общая проблема случая может быть «решена», но она будет сложной и требует использования знаний о том, сколько полей существует в строке и структуре данных этих полей. (И всегда могут быть крайние случаи, оставленные без обслуживания.)


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

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

Это простейшее регулярное выражение, которое будет работать в большинстве случаев:

 Capturing Group 1 Capturing Group 2 (All previous valid fields) (Unclosed opening quote) __________________________|_________________________ | | || | ^((?:(?:(?!")[^|\r\n]*|"[^"\r\n]*"(?=$|\|))(?:$|\|))*+)(") |____________| |_________________| |______| | | | Unquoted field OR Quoted field EOL or hypen delimiter 

Используйте это с этой строкой замены:

$1\\$2 

демонстрация

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


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

Как побочный эффект своей простоты, регулярное выражение также будет игнорировать кавычки, появляющиеся в середине поля. (Это может или не может быть проблемой.)


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

^((?:(?:(?!")[^|\r\n]*|"[^"\r\n]*"(?:(?=$)|(?=\|)(?!(?:\|[^|"\r\n]*)+[^|\r\n]")))(?:$|\|))*+)(") |____________________________________________| | Modified lookahead to make sure that the following | is not the first char of a properly quoted field 

демонстрация

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

Идеальный ответ. Спасибо, что нашли время и объяснили мне, как будто мне 5. Очень ценю. Rhythem Aggarwal 5 лет назад 0

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