Как заменить мутилинное пространство в sed - PullRequest
0 голосов
/ 10 ноября 2019

У меня есть данные, которые показаны как показано ниже в файле test.cs

using System;
using System.Data;
using Sample.test.value;
namespace Sample.test {

  class testclass{  

    public testclass(){


    }
  }
}

Я хочу, чтобы вывод был

namespace Sample.test {
 using System;
 using System.Data;
 using value;
  class testclass{  

    public testclass(){


    }
  }
}

Этого я хочу достичь только с помощьюsed

Я попробовал приведенный ниже сценарий sed и смог скопировать и вставить внутреннее пространство имен using

/^using/{
 H
 d
}
/^namespace/{
 G
}

Но не смог заменить пространство имен в операторе using. Здесь, в этом примере, я взял пример в качестве пространства имен «Sample.test». Но в действительности это может быть что угодно.

Ответы [ 3 ]

1 голос
/ 11 ноября 2019

Это может работать для вас (GNU sed):

sed '/using/{s/^/ /;s/Sample\.test\.//;H;d};/namespace/{p;g;s/.//;n;/^$/d}' file

Соберите строки, содержащие using в области удержания, но сначала добавьте начальный пробел и удалите все строки Sample.test.. При обнаружении namespace напечатайте эту строку, добавьте пробел, удалите начальную новую строку, напечатайте эти строки, затем выберите следующую и, если она пуста, удалите ее.

1 голос
/ 11 ноября 2019

Этот сценарий sed преобразует ваши тестовые данные, но потребует изменения, если ваши файлы содержат более одного блока, использующего / namespace, или если пробел не идентичен.

# match using lines
/^using/{
    s/^/ /  # prepend whitespace 
    H       # append to hold
    d       # don't print (yet)
}

# match namespace lines
/^namespace/{
    G       # append the using block after namespace line

    # loop while we can strip a namespace name from a using line
    :a
    s/\(\([^ ]*\) {.*using \)\2\./\1/
    ta

    # read in next line and delete it if empty
    N
    s/\n\n/\n/g
}

# implicit print

Вторая команда s/// выглядитдля имени, которое предшествует { (т. е. \([^ ]*\)), за которым следует строка using с тем же именем, за которым следует точка (т. е. \2\.). Полное совпадение, кроме конечного \2\., доступно как \1 из-за начального набора \( ... \) и заменяет исходный текст.


Опираясь на ответ @ Jotne, эквивалентная версия awk выглядит следующим образом:

/^using/ {
    # store using lines, along with a prepended space
    a[++i] = " " $0
    next
}
/^namespace/ {
    print

    # strip namespace name from using lines, then print
    r = " " $2 "[.]"
    for(i in a) {
        sub(r, " ", a[i])
        print a[i]
    }

    # delete subsequent line if it is blank
    getline
    if ($0) print

    next
}

# print every other line
1

Здесь регулярное выражение (r) ищет пробел, за которым следует имя пространства имен (оно должнобыть $2 в строке пространства имен), за которым следует точка. sub() заменяет все вхождения этого регулярного выражения в сохраненных строках, используя только один пробел.

1 голос
/ 11 ноября 2019

Использование awk может подойти. Но не уверен, что вызывает действие и как оно работает с вашими реальными данными.

awk '/^using/ {s=s"\n"$0;next} /^namespace/ {print $0 s;next} 1' file
namespace Sample.test {
using System;
using System.Data;
using Sample.test.value;

  class testclass{

    public testclass(){


    }
  }
}
...