Подтвердить что ты не робот

Vim regex заменяет несколько последовательных пробелов только одним пространством

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

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

Я использую vim, поэтому регулярное выражение в диалоговом окне regex vim было бы очень полезно для меня, если это выполнимо.

Мой текущий ход выглядит следующим образом:

:%s/ \+/ /g

но он работает неправильно.

Я также подумываю написать vim script, который мог бы разобрать текстовые строки один за другим, обрабатывать каждую строку char на char и пропускать пробелы после первого, но у меня такое чувство быть чрезмерным.

4b9b3361

Ответ 1

В интересах прагматизма я обычно делаю это как трехэтапный процесс:

:g/^    /s//XYZZYPARA/g
:g/ \+/s// /g
:g/^XYZZYPARA/s//    /g

Я не сомневаюсь, что может быть лучший способ (возможно, с использованием макросов или даже чистого регулярного выражения), но я обычно считаю, что это работает, когда я спешу. Конечно, если у вас есть строки, начинающиеся с XYZZYPARA, вы можете настроить строку: -)

Достаточно хорошо, чтобы повернуть:

    This is a new paragraph
spanning       two lines.
    And    so    is   this but on one line.

в

    This is a new paragraph
spanning two lines. 
    And so is this but on one line.

Кроме того: если вам интересно, почему я использую :g вместо :s, это просто привычка в основном. :g может делать все :s может и многое другое. Это фактически способ выполнения произвольной команды на выбранных строках. Команда для выполнения в этом случае будет s, поэтому нет никакой реальной разницы, но если вы хотите стать сильным пользователем vi, в какой-то момент вы должны заглянуть в :g.

Ответ 2

это заменит 2 или более пробелов

s/ \{2,}/ /g

или вы можете добавить дополнительное пространство перед \+ к своей версии

s/  \+/ /g

Ответ 3

Это сделает трюк:

%s![^ ]\zs  \+! !g

Многие подстановки могут быть сделаны в Vim проще, чем с другими диалектами regex, используя мета-последовательности \zs и \ze. То, что они делают, состоит в том, чтобы исключить часть матча из конечного результата, либо часть перед последовательностью (\zs, "s" для "start here" ), либо часть после (\ze, "e" для "end Вот" ). В этом случае шаблон сначала должен соответствовать одному непространственному символу ([^ ]), но следующий \zs говорит, что после этого символа начинается окончательный результат сопоставления (который будет заменен).

Поскольку нет способа иметь непространственный символ перед линистым пробелом, он не будет соответствовать шаблону, поэтому замена не заменит его. Простой.

Ответ 4

Здесь есть много хороших ответов (особенно Аристотель: \zs и \ze заслуживают изучения). Просто для полноты вы также можете сделать это с отрицательным утверждением:

:%s/\(^ *\)\@<! \{2,}/ /g

Это говорит "найти 2 или более пробелов (' \{2,}'), которым НЕ предшествует" начало строки, за которой следует ноль или больше пробелов ". Если вы хотите уменьшить количество обратных косых черт, вы также можете сделать это:

:%s/\v(^ *)@<! {2,}/ /g

но это только спасет вас от двух символов! Вы можете также использовать ' +' вместо ' {2,}', если вы не возражаете, чтобы он выполнял нагрузку избыточных изменений (т.е. Менял одно пространство на одно место).

Вы также можете использовать отрицательный внешний вид, чтобы просто проверить один непространственный символ:

:%s/\S\@<!\s\+/ /g

который почти такой же, как (слегка модифицированная версия Aristotle для обработки пробелов и вкладок как одна и та же, чтобы сохранить немного ввода):

:%s/\S\zs \+/ /g

См:

:help \zs
:help \ze
:help \@<!
:help zero-width
:help \v

и (прочитайте все!):

:help pattern.txt

Ответ 5

Это работает?

%s/\([^ ]\)  */\1 /g

Ответ 6

Мне нравится эта версия - она ​​похожа на перспективную версию Aristotle Pagaltzis, но мне легче ее понять. (Возможно, просто мое незнание с \zs)

s/\([^ ]\) \+/\1 /g

или для всех пробелов

s/\(\S\)\s\+/\1 /g

Я прочитал его как "заменил все вхождения чего-то другого, кроме пробела, за которым следуют несколько пробелов с чем-то и одним пространством".

Ответ 7

Ответил; но, несмотря на то, что я бы бросил свой рабочий поток в любом случае.

%s/  / /g
@:@:@:@:@:@:@:@:@:@:@:@:(repeat till clean)

Быстро и просто запомнить. Есть более элегантные решения выше; но только мой .02.