vim regex заменяет несколько последовательных пробелов только одним пробелом - PullRequest
60 голосов
/ 05 октября 2010

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

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

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

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

:%s/ \+/ /g

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

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

Ответы [ 7 ]

106 голосов
/ 05 октября 2010

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

s/ \{2,}/ /g

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

s/  \+/ /g
59 голосов
/ 05 октября 2010

Это поможет:

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

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

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

38 голосов
/ 05 октября 2010

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

: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 в какой-то момент.

7 голосов
/ 05 октября 2010

Здесь есть много хороших ответов (особенно Аристотеля: \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
2 голосов
/ 05 октября 2010

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

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

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

2 голосов
/ 05 октября 2010

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

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

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

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

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

2 голосов
/ 05 октября 2010

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

%s/\([^ ]\)  */\1 /g
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...