Как мне искать строки в файле, которые содержат только символы 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
Используйте расширенное регулярное выражение, чтобы сделать команду более читаемой (нам нужно меньше обратной косой черты) (GNUsed
также признает-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 日本語
日本語のみ