Мне нужно извлечь строки текста из одного файла, содержащего одну очень длинную строку текста без разделителей. Используя пример строки ниже, это следующие известные факты:
A1XXXXXXXXXX ??????? ??????? B1XXXX ??????? A1XXXXXXXXXX ??????? C1XXXXXXX
1. It contains 38 fixed width record types
2. The record marker is a 7 alphanumeric character followed by, for example, ‘A1’.
3. Each record type has varying widths, for example, A1 record type will have 10 characters following it, if B1 then 4, and if C1 then 7.
4. The record types aren’t clumped together and can be in any order. As in the example, its A1,B1,A1,C1
5. The example above has 4 records and each record type needs to go to separate files. In this case 38 of them.
A1XXXXXXXXXX ???????
B1XXXX ???????
A1XXXXXXXXXX ???????
C1XXXXXXX ???????
6. The record identifier, e.g. ????????A1, can appear in the body of the record so cannot use grep.
7. With the last point in mind, I was proposing 3 solutions but not sure on how to script this and of course would greatly appreciate some help.
a. Traverse through the file from the beginning and sequentially strip out the record to the appropriate output file. For example, strip out first record type A1 to A1file which I know is 10 characters long then re-interrogate the file which will then have B1 which I know is 4 chars long, strip this out to B1file etc.. <<< this seems painful >>
b. Traverse through the file and append some obscure character to each record marker within the same file. Much like above but not strip out. I understand it still will use the same logic but seems more elegant
c. I did think of simply using the proposed grep -oE solution but then re-interrogate the output files to see if any of the 38 record markers exist anywhere other than at the beginning. But this might not always work.
text-processing
sed
awk
зазубрины
источник
источник
Ответы:
Как насчет Grep
Это печатает каждую запись каждого типа записи в отдельной строке. Для того, чтобы перенаправить
grep
вывод 3 файлов с именамиA1
,B1
,C1
соответственно,источник
Вот возможное решение с использованием FPAT gawk
Как однострочник:
источник
FPAT
требуется gawk версии 4. См .: linuxjournaldigital.com/linuxjournal/201109#pg98В Perl:
Вызовите это как:
Код проверен и работает с вашим заданным входом.
Обновить
В ваших комментариях вы запросили «Unix-эквивалент» вышеупомянутого. Я очень сомневаюсь, что такая вещь существует, поскольку выражение Perl, используемое для разбора вашей строки, является крайне нерегулярным выражением, и я сомневаюсь, что регулярные выражения ванили могут анализировать заданный вами формат данных: он слишком похож на известный тип выражения, который может использовать регулярное выражение 't parse (соответствует любому числу
a
' s, за которым следует такое же количествоb
's).В любом случае, самый близкий подход «Unix», который я могу найти, - это обобщение ответа 1_CR . Вы должны отметить, что этот подход специфичен для реализации GNU
grep
и поэтому не будет работать на большинстве Unices. Подход Perl, напротив, должен работать одинаково на любой платформе, на которой работает Perl. Вот мой предложенныйgrep
подход GNU :Обновить
Основываясь на запросах OP в комментариях, вместо передачи имени файла в качестве аргумента командной строки, его можно открыть в скрипте следующим образом:
Это предполагает, что вы объявили переменную, которая
$input_file_name
будет содержать имя входного файла.Что касается добавления временной метки к имени выходного файла, вы можете использовать
qx{}
синтаксис: между фигурными скобками вы можете поместить любую команду Unix, которую вы хотите, и она будет выполнена, и ее стандартный вывод будет считан вместоqx{}
оператора:qx
Оператор не ограничивается фигурными скобками, используйте ваш любимый персонаж в качестве разделителя, просто убедитесь , что он не в команде , которую нужно выполнить:и так далее...
В некотором коде Perl вы можете увидеть backticks (
` `
), используемый вместо этой функции, аналогично тому, что делает оболочка. Просто думайте обqx
операторе как об обобщении обратных к любому разделителю.Кстати, это даст немного различную временную метку каждому файлу (если разница времени их создания будет конечным числом секунд). Если вы не хотите этого, вы можете сделать это в два этапа:
источник