Vim regex: перезаписаны обратные ссылки? - PullRequest
3 голосов
/ 09 февраля 2012

Проект:

Возьмите список римских консулов ​​в Википедии, поместите данные в CSV, чтобы я мог составить график роста и падения различных генов с точки зрения консульства

Пример данныхисточник:

509,L. Iunius Brutus,L. Tarquinius Collatinus
suff.,Sp. Lucretius Tricipitinus,P. Valerius Poplicola
suff.,M. Horatius Pulvillus,
508,P. Valerius Poplicola II,T. Lucretius Tricipitinus
507,P. Valerius Poplicola III,M. Horatius Pulvillus II

Поиск по Vim:

/\v(\d+|suff\.),((\w+\.=) (\w+)(\s\w+)=(\s\w+)=(\s[iv]+)=(\s\(.{-}\))=,=){,2}

По существу:

  1. Найти год в начале (или указание на консул суффикса): (\d+|suff\.)
  2. Следующая группа (назовем ее внешней группой) должна быть найдена до двух раз: (outer group){,2}
  3. Для каждой из этих двух внешних групп найдите:
    1. Praenomen, с дополнительным периодом (иногда его нет): (\w+.=)
    2. Номен: (\w+)
    3. Необязательные когномены (включая пробел, как и все ниже): (\s\w+)=
    4. Необязательный agnomen: (\s\w+)=
    5. Необязательная итерация (указывает на n-й раз, когда он был консулом).Источник данных не имеет более 8 итераций (поэтому достаточно I и V): (\s[iv]+)=
    6. Дополнительная пояснительная записка типа "Сициний (Сабин?)": (\s\(.{-}\))=

(Последняя запятая необязательна, так как это конец строки.)

Таким образом, обратные ссылки оказываются:

\1: year or suffect
\2: the entire second outer group
\3: Praenomen of second outer group (same with all below)
\4: Nomen
\5: Cognomen
\6: Agnomen
\7: Iteration
\8: Explanatory note

Проблема в том, что я могуне могу понять, как захватить эту первую внешнюю группу.Это похоже на то, что ссылки \ 2 и \ 3- \ 8 перезаписываются, когда он видит эту вторую внешнюю группу.

Используя эту замену:

:%s//1:{\1}^I2:{\2}^I3:{\3}^I4:{\4}^I5:{\5}^I6:{\6}^I7:{\7}^I8:{\8}^I9:{\9} 

Я получаю такой вывод:

1:{509} 2:{L. Tarquinius Collatinus}    3:{L.}  4:{Tarquinius}  5:{ Collatinus} 6:{}    7:{}    8:{}    9:{}
1:{suff.}   2:{P. Valerius Poplicola}   3:{P.}  4:{Valerius}    5:{ Poplicola}  6:{}    7:{}    8:{}    9:{}
1:{suff.}   2:{M. Horatius Pulvillus,}  3:{M.}  4:{Horatius}    5:{ Pulvillus}  6:{}    7:{}    8:{}    9:{}
1:{508} 2:{T. Lucretius Tricipitinus}   3:{T.}  4:{Lucretius}   5:{ Tricipitinus}   6:{ II} 7:{}    8:{}    9:{}
1:{507} 2:{M. Horatius Pulvillus II}    3:{M.}  4:{Horatius}    5:{ Pulvillus}  6:{ II} 7:{}    8:{}    9:{}

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

Редактировать: Оригинальное название Регулярное выражение Vim (или любое совместимое регулярное выражение): как ссылаться на группу (внутри группы), если внешняя группа повторяется?

Ответы [ 2 ]

4 голосов
/ 09 февраля 2012

Я бы разбил его на подэтапы, используя функции vim вместо того, чтобы делать все это normal (каламбур):

/\v(.{-}),(.{-}),(.*)

Видите, что я сделал?сделав это намного проще и понятнее

Редактировать Получив чуть менее ленивый, давайте определим вспомогательную функцию, разбивающую минимум на 3 подстроки и разделяющую их:Теперь уменьшите подстановку до ( разрывов строк только для SO )

%s/\v(.{-}),(.{-}),(.*)/\=join(
  [submatch(1), Consul(submatch(2)), Consul(submatch(3))], "\t")/g

Выполнение этой красоты на вашем входе дает

509 L.  Iunius  Brutus  L.  Tarquinius  Collatinus
suff.   Sp. Lucretius   Tricipitinus    P.  Valerius    Poplicola
suff.   M.  Horatius    Pulvillus           
508 P.  Valerius    Poplicola   T.  Lucretius   Tricipitinus
507 P.  Valerius    Poplicola   M.  Horatius    Pulvillus

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

:%s/\v(.{-})\t(.{-})\t(.{-})\t(.{-})\t(.{-})\t(.{-})\t(.{-})$/1:{\1}\t2:{\2}\t3:{\3}\t4:{\4}\t5:{\5}\t6:{\6}\t7:{\7}/g

Результат:

1:{509} 2:{L.}  3:{Iunius}  4:{Brutus}  5:{L.}  6:{Tarquinius}  7:{Collatinus}
1:{suff.}   2:{Sp.} 3:{Lucretius}   4:{Tricipitinus}    5:{P.}  6:{Valerius}    7:{Poplicola}
1:{suff.}   2:{M.}  3:{Horatius}    4:{Pulvillus}   5:{}    6:{}    7:{}
1:{508} 2:{P.}  3:{Valerius}    4:{Poplicola}   5:{T.}  6:{Lucretius}   7:{Tricipitinus}
1:{507} 2:{P.}  3:{Valerius}    4:{Poplicola}   5:{M.}  6:{Horatius}    7:{Pulvillus}
3 голосов
/ 09 февраля 2012

Да, группы захвата в повторениях перезаписываются на самые последние совпадающие значения.В соответствии с разделом Повторение и обратные ссылки в нижней части связанной страницы:

Механизм регулярных выражений не заменяет обратные ссылки в регулярном выражении навсегда.Он будет использовать последнее совпадение, сохраненное в обратной ссылке каждый раз, когда его нужно будет использовать.Если при помощи скобок найдено новое совпадение, ранее сохраненное совпадение будет перезаписано.

Вам придется явно выписать определенное количество групп захвата.

I'mне совсем знаком с механизмом регулярных выражений vim, поэтому вот простой пример.
Допустим, ваш текст abc 12 345 6789 xyz.

# with repetition
/^\w+( \d+){1,3} \w+$/

# yields:
# 0: abc 12 345 6789 xyz
# 1:  6789

# -----
# writing out each subpattern
/^\w+( \d+)( \d+)?( \d+)? \w+$/

# yields:
# 0: abc 12 345 6789 xyz
# 1:  12
# 2:  345
# 3:  6789

Обратите внимание, что с диапазоном повторения {1,3} я сделал второйи третий ( \d+) опционально с ?.

...