Любой текстовый редактор, который может применить некоторую математику к тексту замены?

15

У меня большой XML-файл

<obj param="2542">
<obj param="2333">
<obj param="6433">

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

Serg
источник
1
Какая операционная система? Вы были бы счастливы вместо сценария оболочки (который был бы довольно легко)? Во всяком случае, я уверен, vimи emacsмогу делать такие вещи, но это может потребовать написания сценария, а не использования одной команды.
безумно
@ frabjous под окнами. Я бы предпочел не писать ничего, если это возможно. Но если вы разместите сценарий оболочки, я уверен, что он будет полезен для многих.
Serg

Ответы:

18

Немного потрудившись, выясняется, что vim может сделать это одной командой без сценариев. Например, чтобы добавить 50 ко всем следующим номерам, <obj param="вы можете использовать:

:%s@<obj param="\(\d\+\)@\='<obj param="' . (submatch(1) + 50)@g

Позвольте мне сломать это.

: это общий способ войти / указать режим командной строки в vim.

%средства в объеме всего документа; Вы можете указать диапазон номеров, например, 1,50сделать это в первых 50 строках.

s является сокращением для замены (вы можете написать все слово, если хотите)

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

Все до следующего вхождения разделителя @ является шаблоном reg ex для поиска, в данном случае <obj param="за \d\+которым следует любое количество цифр. \(И \)там , чтобы установить всю эту последовательность цифр в качестве одной Изотерм бывшей группы , которая будет соответствовать как обратные ссылки \1, или VIM в submatchкоманде.

Затем разделитель @помечает то, что следует за текстом замены.

Здесь \=в начале здесь подразумевается подстановка результата некоторого вычисленного выражения, а не шаблона или строки reg ex, которые здесь являются ключевыми.

Затем мы имеем '<obj param="'для начала замену текста. Далее .следует функция vim для объединения строк.

submatch(1)является встроенной функцией vim, которая может использоваться только внутри команды подстановки и возвращает строку, которая совпадает с регулярным выражением \1; вы бы использовали submatch(2)для эквивалентных регулярных выражений \2и так далее. ( \0Это весь подходящий шаблон, но мы не хотим , чтобы здесь) . В \(и \)в шаблоне поиска используются для разметки , что считается submatch(1).

Следовательно, (submatch(1) + 50)дает результат добавления 50 к числу, за которым следуют цифры <obj param="в форме поиска.

Разделитель @снова используется для выделения конца текста замены.

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

Вы можете, вероятно, решить, как складывать разные числа, или вычитать, или делить, и т. Д.

радостный
источник
Это здорово, у меня был файл GPX, который был поврежден, потому что значения долготы были совершенно недействительными. К счастью, широта была в порядке, поэтому, используя карту, я смог определить, каким должно быть первое правильное значение, выполнить некоторые математические расчеты и определить, что мне нужно вычесть 4294.567548 из каждого значения, чтобы получить его правильно. Единственным камнем преткновения, который у меня был, было то, что этот метод не работал с числом с плавающей запятой, поэтому я просто делал каждую сторону десятичной запятой в качестве отдельных замен, одну -4294 и одну -567548.
Stuff
7

В Emacs (начиная с версии 23): используйте \,для выполнения произвольного кода на Лиспе при замене регулярного выражения . Например, чтобы возвести в квадрат числа, которые вы могли бы использовать

M-x replace-regexp
param="\([0-9]+\)"
param="\,(* \#1 \#1)"

В Vim: начните замену текста с \=(см. :help sub-replace-special). Например, чтобы возвести в квадрат числа:

s!param="\([0-9]\+\)"!\='param="'.submatch(1)*submatch(1).'"'!

Несколько редакторов позволяют вам делать такие вещи с макросами: определить макрос, который 1. ищет следующее совпадение и 2. выполняет замену (используя внешний инструмент для арифметики при необходимости); Повторите макрос столько раз, сколько у вас совпадений.

Жиль "ТАК - перестань быть злым"
источник
Недооцененный ответ. Коротко и вы охватываете 2 редактора + общий случай.
Дерекв
1

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

/[0-9]{1,}

затем нажмите q и a (сохранить макрос в регистре a). После этого нажмите Ctrl-X (увеличив число на 1) и затем нажмите n (для следующего результата поиска). После этого нажмите q еще раз, чтобы сохранить макрос. Теперь вы можете применить макрос к следующему номеру, нажав @ + a. Это изменит текущий номер и перейдет к следующему. Повторяя это или используя x @ a, вы можете повторить это x раз.

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

evnu
источник
Что если мне нужно изменить число не на 1, а на миллион? Или, может быть, использовать умножение / деление?
Serg
1
Это просто, если вы хотите добавить константу x к каждому числу: x + Ctrl + a. Вам нужно добавить разные номера?
Евну