У меня есть большой (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/ любом другом языке сценариев, учитывая, что код имеет небольшой вес.

1 ответ1

1

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

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

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .