Как заменить конечную строку фиксированным текстом, если следующая строка начинается с определенного набора символов?

726
Juhele

У меня есть несколько больших файлов с некоторыми измерениями.

Это выглядит так:

N 12344;PE 9.9999999;... #S 0 0 31 44 75 130 165 196... #S_+ "2 5 2 3 3 1 1 2 3 1 2 2...  N 12345;PE 9.9999999;... #S 0 0 34 57 84 133 152... #S_+ "1 0 1 1 2 3 0 0 0...  N 12346;PE 9.9999999;... #S 0 0 31 44 73 140 169... #S_+ "3 3 4 0 0 2 1 2 4...  N 25104;PE 9.9999999;... #S 0 0 36 52 102 108 145... #S_+ "1 1 0 1 0 0 3 0 1...  N 25105;PE 9.9999999;... #S 0 0 32 58 88 130 143... 

Образец здесь: http://pasted.co/d9806b7c4

Файл намного больше, но я заменил часть данных на «...», чтобы сделать его короче.

Мне нужно как-то заменить концы строки перед "#S" - фактически просто объединить строку "N" со следующими двумя в одну строку (или со следующими тремя, чтобы я мог избавиться от пустых строк). Ожидайте вывод, как это:

N 12344;PE 9.9999999; #S 0 0 31 44 75 130 165 196 #S_+ "2 5 2 3 3 1 1 2 3 1 2 2... N 12345;PE 9.9999999; #S 0 0 34 57 84 133 152 #S_+ "1 0 1 1 2 3 0 0 0... N 12346;PE 9.9999999; #S 0 0 31 44 73 140 169 #S_+ "3 3 4 0 0 2 1 2 4... N 25104;PE 9.9999999; #S 0 0 36 52 102 108 145 #S_+ "1 1 0 1 0 0 3 0 1... N 25105;PE 9.9999999; #S 0 0 32 58 88 130 143... 

Можно ли добиться этого с помощью какой-либо утилиты командной строки в Linux?

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

Спасибо

2
спасибо за помощь в написании кода :-) Juhele 5 лет назад 0
@Pimp Juice IT: ОК, я обновил вопрос. Juhele 5 лет назад 1
Привет @Juhele, можешь ли ты лучше указать выходной формат: тебе нужно обрезать первую строку после, например, `PE 9.9999999;`, тебе нужно обрезать вторую после 7-го (8-го) числа или, как ты пишешь, _merge " N "строка со следующими двумя Как насчет `" `присутствующего только в выходных данных?! Я даю некоторую правку вашему посту, пожалуйста, проверьте его. Это может быть неполный файл? Кстати, для самого простого случая у вас уже есть более одного хорошего ответа. Hastur 5 лет назад 0

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

4
xenoid

С помощью sed:

sed -z -e 's/\n#S/ #S/g' -e 's/\nN /N /g' data 

В замедленном режиме:

  • -z заставляет sed рассматривать файл как одну строку (таким образом, концы строк представляют собой простые символы)
  • 's/\n#S/#S/g'заменяет все LF, происходящие непосредственно перед #Sa пробелом
  • -e 's/\nN /N /g'заменяет все LF до N(то есть, пустые строки)
4
xenoid

С paste(для этого необходимо всегда иметь группы из 4 строк):

 paste -s -d ' \n' data 

В замедленном режиме:

  • paste -s объединяет строки из файла
  • -dуказывает символы для вставки в качестве разделителей. Когда есть несколько символов, они используются в циклическом режиме, то есть с 3 пробелами и LF:
    • первый пробел используется в первом соединении ( Nдо #S),
    • второе пространство используется на втором соединении ( #Sдо #S),
    • третье место используется в третьем соединении ( #Sдо пустой строки),
    • последний разделитель, LF, используется в четвертом соединении (пустая строка в N)
    • и цикл повторяется для следующих 4 строк.
4
Kamil Maciorowski

Это портативное решение с POSIXsed, реализующее следующие правила:

  • пустые строки должны быть удалены;
  • любая строка, начинающаяся с, #Sдолжна быть объединена с предыдущей непустой строкой, с одним пробелом между ними, если нет предыдущей непустой строки.

Код:

<data sed '/^$/ d; :start; N; s/\n$//; t start; s/\n#S/ #S/; t start; P; D' 

То же самое с комментариями (все еще рабочий код):

<data sed ' /^$/ d # If empty line read, delete it and start a new cycle. :start # A label. N # Read additional line, there are now two lines in the pattern space. s/\n$// # If the second line is empty, replace the newline with nothing. t start # If the above replacement occurred, go to start (to add another line). # Otherwise s/\n#S/ #S/ # if the second line starts with #S, replace the newline with space. t start # If the above replacement occurred, go to start (to add another line). # Otherwise # (i.e when non-empty line not starting with #S occurred) P # print the pattern space up to the first newline and... D # delete the initial segment of the pattern space # through the first newline (i.e. everything just printed), # and start the next cycle with the resultant pattern space # and without reading any new input # (in our case the new input will be explicitly read by N then). ' 

Обратите внимание, что решение использует sedпространство шаблонов для накопления множества входных строк. Это замечание относится:

Пространство шаблона и места хранения должно содержать не менее 8192 байтов.

Непосредственно перед Pкомандой пространство шаблона содержит одну (относительно длинную) строку, предназначенную для печати, и одну (относительно короткую) строку ввода, а также новую строку между ними. Очевидно, это зависит от ваших данных, превышает ли такая структура 8192 байта в какой-то момент. Если это произойдет, некоторые sedреализации могут потерпеть неудачу.

3
Toto

Использование Perl:

perl -0 -ape 's/\R(?=\RN|#)/ /g' file.txt N 12344;PE 9.9999999;... #S 0 0 31 44 75 130 165 196... #S_+ "2 5 2 3 3 1 1 2 3 1 2 2... N 12345;PE 9.9999999;... #S 0 0 34 57 84 133 152... #S_+ "1 0 1 1 2 3 0 0 0... N 12346;PE 9.9999999;... #S 0 0 31 44 73 140 169... #S_+ "3 3 4 0 0 2 1 2 4... N 25104;PE 9.9999999;... #S 0 0 36 52 102 108 145... #S_+ "1 1 0 1 0 0 3 0 1... N 25105;PE 9.9999999;... #S 0 0 32 58 88 130 143... 

Regex объяснить:

s/ : substitute \R : any kind of line break (ie. \r, \n, \r\n) (?= : positive lookahead, zero-length assertion that make sure we have after \RN : a line break followed by letter N | : OR # : # character ) : end lookahead / /g : replace with a space, global 
3
Hastur

awk ( gawk [ 1 ] )

Как обычно, кроме sedвы можете использовать awk(и по-разному ...)

awk 'ORS=" "; NR % 4 == 0 && ORS="\n" ' data 

где

  • ORS=" " исправляет разделитель выходной записи, по умолчанию символ новой строки, в пробел (вы можете изменить)
  • NR % 4 == 0 && ORS="\n" каждая 4-я строка фиксируется обратно на новую строку \n
  • Если ничего не указано, awkпечатается полная строка
  • data это ваш файл данных.

Если вы хотите, вы можете использовать регулярные выражения, как в sed(аналогичным образом).


Версия для проверки формата с awk

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

awk '  else { print "Ohi " > "/dev/stderr" ; exit 65; } }' data 

где

  • a=$0; помещает полную строку в переменную a
  • getline b; читает строку и помещает переменную b
  • getline c; непонятная непостижимая команда :-)
  • if (getline) если он умеет читать строку ...
  • .............. печатает 4 строки
  • else выводит ошибку на устройство stderr (экран или другое), которое вы можете настроить здесь ...
  • exit 65 вернуть код выхода, отличный от 0 --->error

Бонус: почему 65?

В поисках подходящего значения для вашего кода выхода [ 2 ] вы можете обнаружить, что его рекомендуется найти /usr/include/sysexits.hсреди некоторых стандартов C ...

 #define EX_DATAERR 65 /* data format error */ 

65 является наиболее подходящим для ошибки формата данных ...

Честно говоря, в качестве ответа я предпочел 42,
но каждое значение, отличное от нуля (и не зарезервированное [ 2 ] ), может быть хорошим, а 65 - конкретным ...

Однако есть один недостаток: последний пакет строк может состоять из трех (то есть без пустой строки в самом конце); или не может. Если три, то последний символ вашего вывода - это пробел, а не перевод строки. POSIX [определяет «линию»] (http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206) как `последовательность из нуля или более символы плюс завершающий character`. Это, вероятно, будет иметь [обратный эффект, если выходные данные будут проанализированы далее] (https://stackoverflow.com/a/7741505). Kamil Maciorowski 5 лет назад 0
Хотя это и неплохо, но OP, среди некоторых других точек, которые не были полностью определены, содержит наборы из 4 строк, последняя из которых _blank_. Однако с усеченным файлом следующая неизвестная обработка может быть скомпрометирована. Проверка запрошенных форматов выходит за рамки этого потока, и, по-моему, хорошей практикой является ___ генерировать ошибку__. Если вам требуется _solidity_, лучше выбрать сценарий (`awk`,` sed`, `perl` - языки сценариев), который также позволяет воспроизводить обработку данных. Затем вы должны решить, как справиться с ошибками, но это еще один вопрос ... `:-)` Я просто стараюсь сделать это простым. Hastur 5 лет назад 0
@KamilMaciorowski ... тем не менее я добавил еще одну версию с проверкой ошибок ... Hastur 5 лет назад 0
0
KaRolthas

Вы можете сделать это с помощью любого текстового редактора, который поддерживает регулярные выражения, такие как Notepad ++.

Новая строка - это просто непечатаемый символ или два символа. В Windows обычно CarrigeReturn и LineFeed, а в Unix-системах обычно только LineFeed.

Чтобы увидеть их, вам нужно включить показ непечатного символа (обычно это значок абзаца). Смотрите здесь: https://imgur.com/cqiTvrp

Теперь вам нужно использовать заменитель регулярного выражения (CTRL + H) для замены CRLF # S на #S. Символом для CR является \ r, а для LF - \ n. Таким образом, вы получите \ r \ n # S или \ n # S для #S. https://imgur.com/GoeVn70

Или вы можете заменить его на пробел, если вам нужно.

Вопрос с тегом "Linux" .... xenoid 5 лет назад 0
Я думаю, что регулярные выражения в Geany одинаковы. В качестве примера используется Notepad ++, потому что я сейчас нахожусь в Windows. KaRolthas 5 лет назад 0
Вопрос также просит утилиту командной строки ... xenoid 5 лет назад 0
Здорово, работает. Теперь мне нужно как-то обработать хотя бы несколько файлов, так что даже Notepad ++ помогает, когда я работаю на другом компьютере с Windows. Спасибо Juhele 5 лет назад 0

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