В статье, Регулярных выражениях Vim, Oleg Raisky дает следующую команду для сокращения нескольких пустых строк до единственного пробела:
:g/^$/,/./-j
Кто-то может описать, как это работает?
Я знаю :g
команда и регулярные выражения. Но я не понял что часть /,/./-j
делает.
Это действительно гениально. Давайте разберемся с этим. Команда ex
g/^$/xyzzy
будет искать все пустые строки и выполнять команду xyzzy
(произвольная команда ex
) для каждой из них.
Сложность здесь в том, что команда xyzzy
в вашем случае является еще одной командой замены :
,/./-j
, /. / -
задает диапазон. Он имеет форму <начало>, <конец>
и, поскольку перед запятой ничего нет, предполагается, что текущая строка (та, где вы нашли пустую строку) является началом.
После запятой стоит /./-
, что означает поиск следующего символа (.
означает любой символ), затем вернуться на одну строку ( /./-
- это сокращение от /./- 1
, поскольку оно подразумевается, если значение не задано). Вы найдете этот образец .
в первой непустой строке после строки, с которой вы работаете.
Другими словами, конец диапазона - это последняя пустая строка после или рядом с той, с которой вы сейчас работаете.
Затем вы выполняете соединение в этом диапазоне.
Если начало и конец диапазона были равны (в разделе была только одна пустая строка), объединение ничего не делает. Если они не равны, join объединит их всех.
Это способ объединения нескольких пустых строк в одну.
Давайте посмотрим на пример (номеров строк нет в файле):
1 Line 1
2
3 Line 3
4 Line 4
5
6
7
8
9 Line 9
Команда : g
найдет все пустые строки и выполнит над ними свою операцию (строки 2, 5, 6, 7 и 8).
Для строки 2, , /. / - j
установит диапазон от 2 до 2 (следующий .
находится в строке 3, затем вычтите 1). Соединение в диапазоне 2,2 ничего не делает.
Для строки 5 , /. / - j
задает диапазон от 5 до 8 (следующий .
находится в строке 9, затем вычтите 1). Соединение в диапазоне 5,8 соединит все эти строки вместе.
Я не полностью в этом уверен, но я думаю, что операция не может выполняться на строках, которые исчезают как часть более ранней операции. Это потому, что не имеет смысла обрабатывать строки, которые были удалены ранее в цикле.
Другими словами, поскольку строки с 6 по 8 удалены (вместе со строкой 5), глобальная команда после этого не работает с ними. Я основываю это не более чем на том факте, что в документации vim указан двухпроходный алгоритм: один для маркировки строк, другой для выполнения операции.
Я могу ошибаться в этом вопросе (это будет не в первый раз), но это деталь реализации, которая не влияет на функциональность.