Каков наилучший подход к этой замене в Vim? - PullRequest
2 голосов
/ 26 декабря 2011

Несколько строк документа имеют заголовок / заголовок раздела, а затем около 10 списков под каждым.Мне нужно добавить информацию заголовка / заголовка в каждый из списков, чтобы их можно было правильно загрузить на сайт (используя разделители запятой и канала).Это выглядит так:

SectionName1 and TitleName1
     1111 - The SubSectionName A

     222 - The SubSectionName B

     3333 - The SubSectionName C

SectionName2 and TitleName2
     444 - The SubSectionName D

     55555 - The SubSectionName E

     66 - The SubSectionName F

Повторяется несколько сотен раз.Что мне нужно, это создать что-то вроде:

SectionName1,TitleName1,1111,SubSectionNameA
SectionName1,TitleName1,222,SubSectionNameB
SectionName1,TitleName1,3333,SubSectionNameC
SectionName2,TitleName2,444,SubSectionNameD
SectionName2,TitleName2,55555,SubSectionNameE
SectionName2,TitleName2,66,SubSectionNameF

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

Любая помощь, которая поможет мне начать умственно начинаться, будет принята с благодарностью.

Ответы [ 3 ]

5 голосов
/ 27 декабря 2011

Позвольте мне предложить следующую довольно общую команду Ex, решающую выпуск. 1

:g/^\s*\h/d|let@"=substitute(@"[:-2],'\s\+and\s\+',',','')|ki|/\n\s*\h\|\%$/kj|
\   'i,'js/^\s*\(\d\+\)\s\+-\s\+The/\=@".','.submatch(1).','/|'i,'js/\s\+//g

На верхнем уровне это команда :global, которая перечисляет строки начиная с нуля или более пробельных символов, за которыми следует латинская буква или подчеркивание (см. :help /\h). Предполагается, что линии, соответствующие этому шаблону быть строкой заголовка, содержащей названия разделов и заголовков. Остаток от После шаблона, описывающего строки заголовка, команда выполняется для каждой из этих строк.

Действия над заголовками можно разделить на три этапа.

  1. Удалить текущую строку заголовка, одновременно извлекая раздел и названия из него.

    :d|let@"=substitute(@"[:-2],'\s\+and\s\+',',','')
    

    Сначала удалите текущую строку, сохранив ее в безымянном регистре, используя команду :delete. Затем обновите содержимое этого регистр (именуемый @"; см. :help @r и :help "") для результат подстановки: изменение слова and в окружении пробельные символы, до одной запятой. Фактическая замена выполняется функцией substitute().

    Однако, ввод не является точной строкой, содержащей весь заголовок строка, но ее префикс пропускает последний символ, который символ новой строки. Запись [:-2] является краткой формой [0:-2] подстрочное выражение, обозначающее подстроку из от первого байта до второго, считая от конца (см. :help expr-[:]). Таким образом, безымянный регистр содержит раздел и названия заголовков через запятую.

  2. Определить диапазон зависимых линий подразделов.

    :ki|/\n\s*\h\|\%$/kj
    

    После первого шага записи подраздела принадлежат только разобранные строки заголовка расположены начиная с текущей строки после заголовка) до следующей строки заголовка или, если нет такая строка ниже, конец буфера. Номера этих строк хранится в отметках i и j соответственно. (См. :helpg ^A mark is для описания маркировки.)

    Метки ставятся с помощью команды :k, которая устанавливает указанную метку в последней строке заданного диапазона, который является текущей строкой, дефолт. Итак, в отличие от первой строки рассматриваемого блока, последняя каждый требует определенного диапазона линии, чтобы указать его местоположение. Определенная форма диапазона, обозначающая следующую строку, где задан Соответствие шаблону, используется в этом случае (см. :help :range). шаблон, определяющий местоположение найденной линии, состоит из таким образом, что он соответствует строке, непосредственно предшествующей заголовку ( строка, начинающаяся с возможного пробела, за которой следует алфавитный символ), или самая последняя строка. (Подробнее см. :help pattern о синтаксисе регулярных выражений Vim.)

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

    :'i,'js/^\s*\(\d\+\)\s\+-\s\+The/\=@".','.submatch(1).','/|'i,'js/\s\+//g
    

    Этот шаг состоит из двух команд :substitute, которые выполняются в диапазоне линий, ограниченных местами, помеченными отметки i и j (см. :help [range]).

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

    Для построения замещающей строки в первом :substitute В команде используется функция замены выражением (см. :help sub-replace-\=). Подстановочная часть команды должна начаться с \= для Vim, чтобы интерпретировать оставшийся текст не в обычном Кстати, но как выражение (см. :help expression). Результат оценка этого выражения становится строкой подстановки. Заметка использование функции submatch() в выражении замены для извлечения текста субматча по его номеру.


1 Команда лучше переноситсяудобочитаемость, его однострочная версия приведена ниже для простоты копирования в командную строку Vim.Обратите внимание, что обернутая команда может использоваться в скрипте Vim без каких-либо изменений.

:g/^\s*\h/d|let@"=substitute(@"[:-2],'\s\+and\s\+',',','')|ki|/\n\s*\h\|\%$/kj|'i,'js/^\s*\(\d\+\)\s\+-\s\+The/\=@".','.submatch(1).','/|'i,'js/\s\+//g
2 голосов
/ 26 декабря 2011

Самый простой / быстрый способ, который я могу придумать, - это простой макрос.Сделай один раз, сполосни, повтори.Предполагая, что ваш курсор изначально находится на первом символе первой строки (S в SectionName), этот макрос должен работать до тех пор, пока документ точно в том же формате, что и приведенный выше.

f ctT,<Esc>yyjpjjpjddkkkddkkkJr,f ctS,<Esc>f xjJr,f ctS,f xjJr,f ctS,<Esc>f xjdd
1 голос
/ 27 декабря 2011

ну, я думаю, вопрос не так ясен.почему в вашем демонстрационном вводе, после "-", текст был таким:

55555 - SubSectionName E

, но в ожидаемом выходе, это превратилось в:

55555,SubSectionNameE

все пробелы были удалены, это нормально, но почему "The" также был удален?есть ли шаблон для «the»?

Я написал awk oneliner, он удаляет все пробелы в выводе, но оставляя эти «The» там, вы можете изменить его, чтобы получить правильный вывод, который вам нужен.

awk -F' and '  -vOFS="," 'NF>1{s=$1;t=$2;next;}$1{gsub(/\s+/,"");gsub(/-/,",");print s,t,$0} ' input

проверка на вашем примере ввода:

kent$  cat v
SectionName1 and TitleName1
     1111 - The SubSectionName A

     222 - The SubSectionName B

     3333 - The SubSectionName C

SectionName2 and TitleName2
     444 - The SubSectionName D

     55555 - The SubSectionName E

     66 - The SubSectionName F

kent$  awk -F' and '  -vOFS="," 'NF>1{s=$1;t=$2;next;}$1{gsub(/\s+/,"");gsub(/-/,",");print s,t,$0} ' v
SectionName1,TitleName1,1111,TheSubSectionNameA
SectionName1,TitleName1,222,TheSubSectionNameB
SectionName1,TitleName1,3333,TheSubSectionNameC
SectionName2,TitleName2,444,TheSubSectionNameD
SectionName2,TitleName2,55555,TheSubSectionNameE
SectionName2,TitleName2,66,TheSubSectionNameF
...