Как мне искать строки в файле, которые содержат только символы ASCII, а затем воздействовать на них?

У меня есть текстовый файл, который выглядит так:

English words only
English and 日本語
日本語のみ
English words only
English and 日本語
日本語のみ
English words only
Also English words only
English and 日本語
日本語のみ
English words only
English and 日本語
日本語のみ

Обратите внимание, что в середине есть две строки, English words only а также Also English words only один за другим.

Что мне нужно сделать, это взять эти две строки, и объединить в одну строку, разделенную /, как это:

English words only
English and 日本語
日本語のみ
English words only
English and 日本語
日本語のみ
English words only / Also English words only
English and 日本語
日本語のみ
English words only
English and 日本語
日本語のみ

Я обнаружил, что могу искать строки с символами ASCII с помощью следующего регулярного выражения: [[:ascii:]] и для не ASCII с [^[:ascii:]], Однако у меня возникли небольшие проблемы с использованием регулярных выражений для поиска случаев несоответствия условию, поскольку мне нужно искать строки без символов ASCII.

Я нашел этот вопрос о "обратном сопоставлении", но ответы там за пределами меня.

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

Есть ли способ найти все строки без символов, отличных от ASCII, а затем объединить их, используя LibreOffice, Gedit или командную строку?

Обратите внимание, что файл имеет длину в тысячи строк, и я также не уверен, но возможно, что в нем есть только строки на английском языке, которые находятся в группах по 3 или 4.

2 ответа

Решение

Кажется, вы можете использовать sed чтобы сделать эту работу, даже если он не знает о [[:ascii:]] класс персонажей. Вместо этого мы можем указать все символы ASCII с диапазоном escape-последовательностей.[\d0-\d127]До тех пор, пока мы используем C или же POSIX локали.

Вот команда, которая должна быть надежной:

LC_ALL=C sed -r ':a;N;s|^([\d0-\d127]+)\n([\d0-\d127]+)$|\1 / \2|;ta' file

Заметки

  • LC_ALL=C использование C Настройки локали только для этой команды (в противном случае вы получите ошибку)
  • -r Используйте расширенное регулярное выражение, чтобы сделать команду более читаемой (нам нужно меньше обратной косой черты) (GNU sed также признает -E с тем же значением).
  • :a Метка - цикл начинается здесь
  • ; Отдельные команды, как в оболочке
  • N Прочитайте следующую строку в пространстве шаблона, чтобы мы могли заменить \n
  • s|old|new| замещать old с new
  • ^([\d0-\d127])\n([\d0-\d127]+)$ - сопоставить две строки только с ASCII и захватить первую строку в \1 и вторая строка в \2, ^ это начало строки, \n перевод строки, и $ это конец строки, так ^line 1\nline 2$ тестирует весь line 1 а также line 2,
  • \1 / \2 Первая и вторая строки, разделенные  /  вместо новой строки.
  • ta - Если последняя команда поиска и замены выполнена успешно, повторите цикл снова. Это позволяет нам обрабатывать все строки файла, обрабатывая любые экземпляры, в которых имеется более двух строк всего ASCII.

Большое спасибо Eliah Kagan за то, что он показал мне, как использовать escape-последовательности для соответствия символам ASCII.

Если вы хотите, чтобы целые строки состояли только из символов ASCII, вам нужно привязать ваш шаблон к началу и концу строки, например, с помощью grep

$ grep -P '^[[:ascii:]]*$' file
English words only
English words only
English words only
Also English words only
English words only

Некоторые инструменты предоставляют флаг целой строки, такой как grep's -x или же --line-regexp:

   -x, --line-regexp
          Select  only  those  matches  that exactly match the whole line.
          For a regular expression pattern, this  is  like  parenthesizing
          the pattern and then surrounding it with ^ and $.

позволяет вам использовать:

$ grep -Px '[[:ascii:]]*' file
English words only
English words only
English words only
Also English words only
English words only

Многострочное сопоставление добавляет еще один уровень сложности, поскольку многие из общих утилит обработки текста в командной строке основаны на строках. Вы можете заставить grep хлебать целый файл, используя -Z пометить однако есть такие инструменты, как pcregrep или же perl само по себе, вероятно, более уместно в этой точке.

Следующая проблема, которую вам нужно решить, - это как интерпретировать понятия "начало строки" и "конец строки" в контексте многострочного соответствия. Некоторые инструменты предоставляют флаги для этого, как описано в Regex Tutorial: Anchors: perl является одним из них, который обеспечивает /m модификатор. Вам все еще нужно удалить файл, удалив разделитель записей по умолчанию (здесь делается с помощью -0777); например

$ perl -0777 -pe 's{^([[:ascii:]]+)\n([[:ascii:]]+)$}{$1 / $2}mg' file
English words only
English and 日本語
日本語のみ
English words only
English and 日本語
日本語のみ
English words only / Also English words only
English and 日本語
日本語のみ
English words only
English and 日本語
日本語のみ
Другие вопросы по тегам