как удалить символ новой строки с помощью Sed или perl [дубликат]

Вопрос или проблема

У меня есть большой файл с данными XML, содержащий строки, подобные

<fonts> часть данных </fonts>
<fonts> часть данных </fonts>
<fonts> часть
 данных </fonts>
<fonts> часть данных </fonts>
<fonts> часть данных </fonts>

Между ними я получаю символ новой строки…

$>uname -a
SunOS ******* 5.11 SunOS_Development

Дан файл XML file.xml:

<?xml version="1.0"?>
<root>
  <fonts> часть данных </fonts>
  <fonts> часть данных </fonts>
  <fonts> часть
данных </fonts>
  <fonts> часть данных </fonts>
  <fonts> часть данных </fonts>
</root>

Вы можете применить функцию XPath normalize-spaces ко всем узлам fonts с помощью XMLStarlet:

$ xmlstarlet ed -u '//fonts' -x 'normalize-space()' file.xml
<?xml version="1.0"?>
<root>
  <fonts>некоторая часть данных</fonts>
  <fonts>некоторая часть данных</fonts>
  <fonts>некоторая часть данных</fonts>
  <fonts>некоторая часть данных</fonts>
  <fonts>некоторая часть данных</fonts>
</root>

Это удаляет лишние пробелы и заменяет все другие пробелы на одиночные пробелы во всех узлах fonts.

Если вы хотите только удалить новые строки из данных узлов fonts:

$ xmlstarlet ed -u '//fonts' -x 'translate(., "'$'\n''", "")' file.xml
<?xml version="1.0"?>
<root>
  <fonts> часть данных </fonts>
  <fonts> часть данных </fonts>
  <fonts> часть данных </fonts>
  <fonts> часть данных </fonts>
  <fonts> часть данных </fonts>
</root>

Это зависит от того, что ваша оболочка заменяет $'\n' на буквальный символ новой строки.

Стандартный метод – это команда tr. XML может иметь (и обычно имеет) очень длинные строки, потому что пробелы не являются частью спецификации XML. Большинство текстовых команд Unix основаны на строках, и очень длинные строки, скорее всего, создадут проблемы, такие как sed или awk (в Linux это обычно просто приводит к значительным потерям производительности). Команда tr не должна заботиться о строках, поэтому она может хорошо обрабатывать эти данные.

tr -d '[\r\n]' <inFile > outFile

Тем не менее, меня беспокоит ваша третья строка “fonts”, которую вы показываете как разрезанную. Удаление этой новой строки сблизит тексты без каких-либо пробелов. Я знаю, что файлы Excel .xlsx используют новые строки (и символы возврата каретки), когда в ячейке есть многострочный текст.

Почему вам нужно удалять пробелы? Это не должно вызывать проблем. На самом деле, я обычно запускаю XML через “xmllint –format”, потому что это делает его читаемым в редакторах. Он читается обратно в Excel без проблем: я красиво отформатировал XML, импортировал его в Excel, записал обратно в длинные строки и проверил контрольную сумму, и она оказалась идентичной.

Вы можете избежать проблемы с длинными строками в awk, определив RS = “>”. Всегда достаточно > в XML, чтобы избежать длинных строк. Затем awk видит каждую XML-сущность на отдельной строке, с максимум одним текстовым элементом перед ней. Там, где есть настоящие новые строки, они останутся в тексте, поэтому вы увидите ваш третий ввод как

<fonts>
некоторая часть\nданных</fonts>

Затем вы можете заменить каждый NL или CR/LF на ПРОБЕЛ и сохранить формулировку.

Если вам нужен этот код более подробно, спрашивайте.

Если вам интересно, что Excel имеет общего с XML: файл Excel (.xlsx, .xlsm и т.д., а не .xls) – это просто zip-архив множества XML-файлов.

Мы не можем использовать sed s'/\n/ /g'

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

В awk вы можете переключить символ RS ‘конец строки’, чтобы использовался какой-то другой символ, и тогда новые строки останутся нетронутыми. Или (в gawk) вы можете сделать RS пустым, и тогда весь файл будет считаться одной длинной строкой. Я не могу придумать другие стандартные команды, которые позволяют это сделать.

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

Кроме того, у OP SunOS 5.11, и я бы поставил доллар на то, что у него есть ограничение длины строки, например, 2048 символов. Так что общий XML его сломает. Solaris awk ломается на 6144 (6K) символах.

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

Мы можем использовать sed 's/\n/ /g'.

Обратите внимание на пробел после второго прямого слэша, вышеприведенное выражение заменяет все символы новой строки на пробел.

Ответ или решение

Чтобы удалить символ новой строки из текста с использованием инструментов, таких как sed или perl, необходимо обратиться к нескольким аспектам обработки текста и возможности этих утилит. Данная задача может быть актуальна, например, при работе с файлами данных, содержащими XML-структуры. На примере файла XML с тэгами <fonts>, где могут присутствовать нежелательные переносы строк, мы рассмотрим различные подходы.

Проблема

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

Решение с помощью sed

sed – это потоковый редактор, который часто используется для обработки текста в UNIX-подобных системах. Однако важно понимать, что sed работает с текстом, разделённым новыми строками. Мы можем использовать его для объединения текстов и удаления новых строк, но нужно помнить о следующих моментах:

  1. Основная команда:
    Для удаления символов новой строки с помощью sed, мы рекомендуем такую команду:

    sed ':a;N;$!{ba;s/\n/ /g;};P;D' файл.xml > выходной_файл.xml

    Здесь:

    • :a;N;$!{ba; — это часть, которая создает цикл, считывая входные данные в одно выражение между строками.
    • s/\n/ /g; — заменяет все символы новой строки на пробелы.
    • P;D — печатает первую строку и удаляет её.
  2. Замечание о длине строки:
    Учитывайте, что в некоторых системах, особенно таких как SunOS 5.11, могут быть ограничения по длине строки (например, 2048 символов). Это может привести к ошибкам, если вы обрабатываете очень длинные строки.

Решение с помощью perl

perl позволяет более гибко обрабатывать текстовые строки и работать с символами новой строки. В perl можно использовать следующую команду:

perl -0777 -pe 's/\n/ /g' файл.xml > выходной_файл.xml

Здесь:

  • -0777 — указывает, что следует читать файл как единое целое (то есть, не разбивать его на строки).
  • -pe — это флаг, который заставляет perl выполнить код для каждой строки (которая в нашем случае является всем файлом).
  • s/\n/ /g — замена символа новой строки на пробел по всему содержимому файла.

Примечания

  • Удаление символов новой строки может привести к изменению смысла текста. В примере с тегами <fonts>, если между словами не будет пробела, это может нарушить структуру данных. Будьте внимательны и убедитесь, что такие изменения допустимы в вашем контексте.
  • Для улучшения читаемости и дальнейшей работы с XML-файлом также может быть полезно использовать xmlstarlet или xmllint, которые помогут форматировать и нормально структурировать XML.

Заключение

Использование sed и perl для удаления символов новой строки из текстовых файлов является эффективным способом обработки данных. Важно учитывать специфику системы и формата данных, чтобы избежать нежелательных последствий при манипуляциях с текстом. Также стоит помнить о совместимости и взаимодействии с другими системами, при необходимости проверить корректность полученных результатов после манипуляций.

Оцените материал
Добавить комментарий

Капча загружается...