регулярное выражение vim заменяет несколько последовательных пробелов только одним пробелом


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

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

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

мой текущий прогресс выглядит так:

:%s/ +/ /g

но это не работает.

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

7 54

7 ответов:

в интересах прагматизма, я стараюсь просто делать это в три этапа:

: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 power user, вы должны смотреть в :g в какой-то момент.

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

s/ \{2,}/ /g

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

s/  \+/ /g

это будет делать трюк:

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

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

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

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

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

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

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

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

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

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

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

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

посмотреть:

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

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

:help pattern.txt

это работает?

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

мне нравится эта версия-она похожа на версию look ahead Аристотеля Пагальциса, но мне ее легче понять. (Наверное, просто мое незнание \zs)

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

или для всех пробельных символов

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

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

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

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

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