Знайдіть і замініть за допомогою регулярних виразів


26

У мене є файл із купою стандартних налаштувань користувача. Я хочу змінити частину тексту, але я намагаюся придумати відповідник і замінувач. Використовуючи наступний приклад:

###############################################################################
# Trackpad, mouse, keyboard, Bluetooth accessories, and input                 #
###############################################################################

# Trackpad: enable tap to click for this user and for the login screen
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true

Я б хотів замінити # Trackpad: ...наrunning "Trackpad: ..."

Вирішуючи проблему, я придумав щось за допомогою тестера регулярних виразів:

/\n\n#\s(.*)/g

Якщо я спробую використовувати це у Vim, це не працює для мене:

:/\n\n#\s(.*)/running "\1"/g

Я думаю, моя проблема зводиться до двох конкретних питань:

  1. Як я можу уникнути пошуку \nсимволів і замість цього переконатися, що #вони не відображаються в кінці групи пошуку?
  2. Як я можу ефективно використовувати групи захоплення?

Нижче наведено кілька чудових відповідей. Важко вибрати між усіма трьома, проте я вважаю, що обрана відповідь є найбільш точною для моєї оригінальної специфікації. Рекомендую спробувати всі три відповіді з фактичним файлом, щоб побачити, як ви ставитесь до них.

Відповіді:


18

Просто, щоб було зрозуміло ... Я вважаю, ви просили, щоб це було результатом заміни?

###############################################################################
# Trackpad, mouse, keyboard, Bluetooth accessories, and input                 #
###############################################################################

running "Trackpad: enable tap to click for this user and for the login screen"
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true

У такому випадку я рекомендую таку команду:

:%s/\n\n#\s\+\(.*\)/^M^Mrunning "\1"/

Пояснення візерунка

:s/PATTERN/REPLACEMENT/- це команда заміщення . Відсоток входу :%sзмушує працювати над усім файлом, а не лише поточним рядком.

\n\nКаже , що лінія інтересу має відбутися після того, як порожній рядок. Якщо ви не переймалися попереднім порожнім рядком, то цього ^буде достатньо.

#\s\+відповідає символу хеша, за яким слід один або кілька символів пробілу. \(.*\)фіксує весь наступний текст у рядку.

Пояснення тексту заміни

^M^Mвставляє два кінці ліній, щоб замінити ті, \n\nщо були у візерунку. В іншому випадку текст буде переміщений до кінця рядка, що передує порожньому рядку. Щоб ввести кожну ^M, натисніть Ctrl-V Ctrl-M.

Потім вставте рядок running, після чого все, що було захоплено в дужках, у межах подвійних лапок.


Я не можу відредагувати вашу відповідь, але я вважаю, що ви мали на увазі :%s/\v\n\n#\s+(.*)/^M^Mrunning "\1"/(додав "чарівний" прапор). Дійсно важко вибрати правильну відповідь на моє первісне запитання, але я вважаю, що ця відповідь є найближчим до моєї оригінальної очікуваної відповіді. Це також єдиний, який працює у всьому файлі без необхідності вибору діапазону.
squarefrog

1
IIRC ви можете використовувати \rзамість того, ^Mщоб отримувати нові рядки?
муру

11

Я б використав щось на кшталт:

:s/^#\s\+\(.\{-}\):/running "\1":/
  • ^#щоб відповідати #символу, закріпленому на початку рядка (це відповідає на питання 1)
  • \s\+ відповідати будь-якому пробілу один чи більше разів
  • \( створити групу (це відповідає на питання 2)
  • .\{-}\відповідати будь-якому символу 0 або більше разів не жадно ; це відрізняється від того, .*що воно намагається співставити якомога менше, а не максимально. Спробуйте додати :символу в коментар, щоб зрозуміти, чому це має значення
  • \) для закінчення підгрупи.
  • : відповідає буквальному :

Потім ми замінюємо це потрібним текстом і використовуємо \1для позначення групи, яку ми захопили.

Я щось придумав, використовуючи тестер для регулярних виразів

Синтаксис регулярних виразів трохи схожий на синтаксис wiki: їх є купа, всі вони схожі на перший погляд, жоден з них, очевидно, не кращий за будь-який інший, але є багато відмінностей.

Сьогодні так звані регулярні вирази "сумісні з Perl" є де-факто типовим у більшості мов, але регулярні вирази Vim не сумісні з виразами, сумісними з Perl! Синтаксис Vim regexp сягає щонайменше 70-х, коли Перла навіть не було.

Ви можете бачити це в підгрупах, де вам доведеться використовувати, \(а не ((це сумісно з синтаксисом POSIX 'basic', але не з більш поширеним синтаксисом POSIX 'Extended' або синтаксисом Perl). Ви можете керувати цим, додавши \vпрапор у візерунок (Дивіться :help /\vдеталі), це зробить його "більш сумісним", але не повністю (Ви все одно повинні використовувати .{-}для не жадібних сірників, наприклад)

Таким чином, це може пояснити, чому використання "тестеру регулярних виразів" працює майже, але не зовсім, працює.

http://www.vimregex.com/ як хороший огляд / шпаргалка Vim regexps.


1
Відмінна відповідь, особливо з тим, чому регулярний вираз! = Регекс. Що стосується пошуку та заміни, то це трохи складно, оскільки коментар може мати, а може і не мати :. Докладні відомості дивіться в повному файлі github.com/squarefrog/dotfiles/blob/master/osx/…
squarefrog

8

Ти можеш:

  • пошук рядків, які не закінчуються #::/[^#]$/
  • замінити #\s(.*)на початку рядка:s/\v^#\s(.*)/running "\1"/

Щоб використовувати групи, потрібно:

  • вийти з дужок, щоб вони стали частиною синтаксису регулярних виразів: \(.*\)або
  • використовуйте "магію" , починаючи вираз із \v:s/\v...

Поєднання:

:/[^#]$/s/\v^#\s(.*)/running "\1"/

1
Це працює чудово, дякую, що я включив пояснення того, що означають теги, а не просто текст, який мені потрібно було написати.
Квадратний жаба

Дякуємо за те, що ви зрозуміли, що дужки потрібно уникати, щоб стати частиною синтаксису регулярних виразів. У мене завжди були проблеми з групами регулярних виразів, коли вони працювали.
Адама
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.