Vim: удалить текст, соответствующий шаблону, если подсовпадение (1) пусто

Эта командная строка анализирует документ со списком контактов, в котором может быть указан телефон, электронная почта или веб-сайт, а может и не быть. Если у него есть все три, то все работает отлично — добавление возврата из FormatContact() в конце строки для загрузки данных:

silent!/^\d/+1|ki|/\n^\d\|\%$/-1|kj|'i,'jd|let @a = substitute(@",'\s*Phone: \([^,]*\)\_.*','\1',"")|let @b = substitute(@",'^\_.*E-mail:\s\[\d*\]\([[email protected]]*\)\_.*','\1',"")|let @c = substitute(@",'^\_.*Web site:\s*\[\d*\]\([-_.:/0-9a-zA-Z]*\)\_.*','\1',"")|?^\d\+?s/$/\=','.FormatContact(@a,@b,@c)

или в разбивке:

silent!/^\d/+1|ki|/\n^\d\|\%$/-1|kj|'i,'jd
let @a = substitute(@",'\s*Phone: \([^,]*\)\_.*','\1',"")
let @b = substitute(@",'^\_.*E-mail:\s\[\d*\]\([[email protected]]*\)\_.*','\1',"")
let @c = substitute(@",'^\_.*Web site:\s*\[\d*\]\([-_.:/0-9a-zA-Z]*\)\_.*','\1',"")
?^\d\+?s/$/\=','.FormatContact(@a,@b,@c)

Я создал три отдельных поиска, чтобы не сделать ОДИН поиск неудачным, если один атом не совпадет, потому что, опять же, контактная информация может существовать или не существовать для каждого контакта.

Проблема, созданная решением, заключалась в том, что, когда шаблон не совпадает, я получаю весь @" в @a. Вместо этого мне нужно, чтобы он был пустым, когда совпадение не происходит. Мне нужно, чтобы каждая переменная представлялась (телефон, электронная почта, Интернет) независимо от того, пуст он или нет.

  1. Я не вижу никаких флагов, которые можно было бы установить в функции подстановки, которая будет это делать.
  2. Есть ли способ вернуть "", если \1 пусто?
  3. Есть ли способ создать необязательный атом, чтобы поисковый запрос (запросы) все еще мог учитывать пустое совпадение, чтобы правильно записать его как пустое?

person Ricalsin    schedule 11.01.2012    source источник
comment
можете ли вы сделать это немного яснее, что вы пытаетесь сделать? Вы обрабатываете ввод построчно? Кто дергает выбор в первую очередь? Где @a будет использоваться. (Я изо всех сил старался выжать из этого что-то краткое, но, кроме написания функции vimscript, у меня ничего не получалось)   -  person sehe    schedule 11.01.2012
comment
@sehe сообщение было обновлено.   -  person Ricalsin    schedule 12.01.2012


Ответы (2)


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

let @a = matchstr(@", '\<Phone:\s*\zs[^,]*')
let @b = matchstr(@", '\<E-mail:\s*\[\d*\]\zs[[email protected]]*')
let @c = matchstr(@", '\<Web site:\s*\[\d*\]\zs[-_.:/0-9a-zA-Z]*')
person ib.    schedule 12.01.2012
comment
Гуру @ib. Ты великолепен! :) На самом деле я решил это, используя другую технику, которую я узнал от вас (! = сопоставление слов в функции FormatContact), но я знал, что есть лучший способ - я реализовал ваш пост выше. Кажется, я читал о matchstr в справке по vim, но этого слишком много, чтобы запомнить все. Большое спасибо (еще раз). - person Ricalsin; 12.01.2012
comment
Гуру @ib. вы оказали мне исключительную помощь. Я вернусь за добавкой! :) Можете посмотреть на этот пост? stackoverflow.com/questions/8887207/ Спасибо! - person Ricalsin; 17.01.2012
comment
Я получил твое письмо. Спасибо, что прогнал меня! Отвечаю в частном порядке. Сегодня вы должны были получить от меня электронное письмо с моей учетной записи gmail. - person Ricalsin; 18.01.2012

На всякий случай, если вам нужна построчная обработка, рассмотрите возможность использования в сочетании с :global, например.

let @a=""
g/text to match/let @A=substitute(getline("."), '^.*\(' . @/ . '\).*$', '\1\r', '')

Это напечатает соответствующий текст для любой содержащей его строки, разделенной символами новой строки:

echo @a

Прелесть здесь в том, что вы можете очень легко заставить его работать с последним использованным search-pattern:

g//let @A=substitute(getline("."), '^.*\(' . @/ . '\).*$', '\1\r', '')
person sehe    schedule 11.01.2012
comment
Спасибо @sehe, это творческое мышление, и я буду помнить об этом. Я перепостил OP по вашему запросу, чтобы сделать его более понятным. Пожалуйста, взгляните еще раз. Спасибо! - person Ricalsin; 12.01.2012