Bash текст от шаблона к шаблону многострочный - PullRequest
0 голосов
/ 08 мая 2020

У меня есть файл с несколькими сегментами кода. Сегменты разделяются языком с использованием (Language) в качестве разделителя. Я хотел бы иметь возможность извлекать все сегменты одного и того же языка (игнорируя другие сегменты).

Я пробовал использовать grepping для нужного языка (Python) до тех пор, пока NEXT не появится на языке сепаратор, но дело зашло слишком далеко. Я думаю, что этот синтаксис превращает go в LAST языкового разделителя.

cat filename | tr '\n' '@' | grep '@(Python).*@([A-Z].*)' | tr '@' '\n'

Я мог бы сделать это довольно легко с некоторыми построчно лог c. Я ищу простое решение grep, awk или sed.

Входной файл:

(Axiom) [fibonacci(n) for n in 0..50]
(MAGMA) [Fibonacci(n): n in [0..38]];
(MAGMA) [0, 1] cat [n: n in [1..50000000] | IsSquare(5*n^2-4) or IsSquare(5*n^2+4)]; 
(Maxima) makelist(fib(n), n, 0, 100); 
(PARI) a(n) = fibonacci(n)
(PARI) a(n) = imag(quadgen(5)^n)
(PARI) a(n)=my(phi=quadgen(5)); (phi^n-(-1/phi)^n)/(2*phi-1) 
(PARI) a(n)=polcoeff(sum(m=0, n, x^m*prod(k=1, m, k+x +x*O(x^n))/prod(k=1, m, 1+k*x +x*O(x^n))), n) 
(Python) # From Jaap Spies, Jan 05 2007:
def fib():
    """ Generates the Fibonacci numbers, starting with 0 """
    x, y = 0, 1
    while 1:
        yield x
        x, y = y, x+y
f = fib()
a = [next(f) for _ in range(100)]
def A000045(n):
    """ Returns Fibonacci number with index n, offset 0 """
    return a[n]
def A000045_list(N):
    """ Returns a list of the first n Fibonacci numbers """
    return a[:N]
(Python) # As b-file:
from gmpy2 import fib
for n in range(100): print(str(n) + " " + str(fib(n)))  # Bruno Berselli, Dec 06 2016
(Sage) # Demonstration program from Jaap Spies:
a = sloane.A000045; # choose sequence
print(a)            # This returns the name of the sequence.
print(a(38))        # This returns the 38th number of the sequence.
print(a.list(39))   # This returns a list of the first 39 numbers.
(Sage) # Alternatively:
a = BinaryRecurrenceSequence(1, 1); print([a(n) for n in range(20)])
# Closed form integer formula with F(1) = 0 from Paul Hankin (use only for fun).
F = lambda n: (4<<(n-1)*(n+2))
print([F(n) for n in range(20)]) # Peter Luschny, Aug 28 2016

Желаемый результат для Python:

(Python)# From Jaap Spies, Jan 05 2007:
def fib():
    """ Generates the Fibonacci numbers, starting with 0 """
    x, y = 0, 1
    while 1:
        yield x
        x, y = y, x+y
f = fib()
a = [next(f) for _ in range(100)]
def A000045(n):
    """ Returns Fibonacci number with index n, offset 0 """
    return a[n]
def A000045_list(N):
    """ Returns a list of the first n Fibonacci numbers """
    return a[:N]

(Python)# As b-file:
from gmpy2 import fib
for n in range(100): print(str(n) + " " + str(fib(n)))  # Bruno Berselli, Dec 06 2016

Желаемый вывод для Sage:

(Sage) # Demonstration program from Jaap Spies:
a = sloane.A000045; # choose sequence
print(a)            # This returns the name of the sequence.
print(a(38))        # This returns the 38th number of the sequence.
print(a.list(39))   # This returns a list of the first 39 numbers.

(Sage) # Alternatively:
a = BinaryRecurrenceSequence(1, 1); print([a(n) for n in range(20)])
# Closed form integer formula with F(1) = 0 from Paul Hankin (use only for fun).
F = lambda n: (4<<(n-1)*(n+2))
print([F(n) for n in range(20)]) # Peter Luschny, Aug 28 2016

Желаемый вывод для PARI:

(PARI) a(n) = fibonacci(n)
(PARI) a(n) = imag(quadgen(5)^n)
(PARI) a(n)=my(phi=quadgen(5)); (phi^n-(-1/phi)^n)/(2*phi-1) 

Ответы [ 3 ]

2 голосов
/ 08 мая 2020

Я предполагаю, что это просто ошибки в вашем вопросе, что ожидаемый результат для PARI включает (PARI), но результат для Python не включает (Python) (и то же самое для Sage) и этот из (PARI) строк из ввода отсутствует в ожидаемом выходе.

Следующее будет работать с любым awk в любой оболочке в каждом поле UNIX.

Если вам нужен язык имя сохраняется в выводе, тогда:

awk -v tgt='Python' -F'[()]' '/^\(/{f=(tgt==$2)} f' file

в противном случае, если вы хотите его удалить:

awk -v tgt='Python' -F'[()]' '{act=$2} sub(/^\([^()]+\) */,""){f=(tgt==act)} f' file

Например, сохраняя (<language>):

$ awk -v tgt='Python' -F'[()]' '/^\(/{f=(tgt==$2)} f' file
(Python) # From Jaap Spies, Jan 05 2007:
def fib():
    """ Generates the Fibonacci numbers, starting with 0 """
    x, y = 0, 1
    while 1:
        yield x
        x, y = y, x+y
f = fib()
a = [next(f) for _ in range(100)]
def A000045(n):
    """ Returns Fibonacci number with index n, offset 0 """
    return a[n]
def A000045_list(N):
    """ Returns a list of the first n Fibonacci numbers """
    return a[:N]
(Python) # As b-file:
from gmpy2 import fib
for n in range(100): print(str(n) + " " + str(fib(n)))  # Bruno Berselli, Dec 06 2016

.

$ awk -v tgt='Sage' -F'[()]' '/^\(/{f=(tgt==$2)} f' file
(Sage) # Demonstration program from Jaap Spies:
a = sloane.A000045; # choose sequence
print(a)            # This returns the name of the sequence.
print(a(38))        # This returns the 38th number of the sequence.
print(a.list(39))   # This returns a list of the first 39 numbers.
(Sage) # Alternatively:
a = BinaryRecurrenceSequence(1, 1); print([a(n) for n in range(20)])
# Closed form integer formula with F(1) = 0 from Paul Hankin (use only for fun).
F = lambda n: (4<<(n-1)*(n+2))
print([F(n) for n in range(20)]) # Peter Luschny, Aug 28 2016

.

$ awk -v tgt='PARI' -F'[()]' '/^\(/{f=(tgt==$2)} f' file
(PARI) a(n) = fibonacci(n)
(PARI) a(n) = imag(quadgen(5)^n)
(PARI) a(n)=my(phi=quadgen(5)); (phi^n-(-1/phi)^n)/(2*phi-1)
(PARI) a(n)=polcoeff(sum(m=0, n, x^m*prod(k=1, m, k+x +x*O(x^n))/prod(k=1, m, 1+k*x +x*O(x^n))), n)

и его удаление:

$ awk -v tgt='Python' -F'[()]' '{act=$2} sub(/^\([^()]+\) */,""){f=(tgt==act)} f' file
# From Jaap Spies, Jan 05 2007:
def fib():
    """ Generates the Fibonacci numbers, starting with 0 """
    x, y = 0, 1
    while 1:
        yield x
        x, y = y, x+y
f = fib()
a = [next(f) for _ in range(100)]
def A000045(n):
    """ Returns Fibonacci number with index n, offset 0 """
    return a[n]
def A000045_list(N):
    """ Returns a list of the first n Fibonacci numbers """
    return a[:N]
# As b-file:
from gmpy2 import fib
for n in range(100): print(str(n) + " " + str(fib(n)))  # Bruno Berselli, Dec 06 2016

.

$ awk -v tgt='Sage' -F'[()]' '{act=$2} sub(/^\([^()]+\) */,""){f=(tgt==act)} f' file
# Demonstration program from Jaap Spies:
a = sloane.A000045; # choose sequence
print(a)            # This returns the name of the sequence.
print(a(38))        # This returns the 38th number of the sequence.
print(a.list(39))   # This returns a list of the first 39 numbers.
# Alternatively:
a = BinaryRecurrenceSequence(1, 1); print([a(n) for n in range(20)])
# Closed form integer formula with F(1) = 0 from Paul Hankin (use only for fun).
F = lambda n: (4<<(n-1)*(n+2))
print([F(n) for n in range(20)]) # Peter Luschny, Aug 28 2016

.

$ awk -v tgt='PARI' -F'[()]' '{act=$2} sub(/^\([^()]+\) */,""){f=(tgt==act)} f' file
a(n) = fibonacci(n)
a(n) = imag(quadgen(5)^n)
a(n)=my(phi=quadgen(5)); (phi^n-(-1/phi)^n)/(2*phi-1)
a(n)=polcoeff(sum(m=0, n, x^m*prod(k=1, m, k+x +x*O(x^n))/prod(k=1, m, 1+k*x +x*O(x^n))), n)

Второй сценарий выше устанавливает разделитель полей на ( или ), сохраняет фактический язык, взятый между ними в переменной с именем act, удаляет (...), затем устанавливает флаг f на 1 (т.е. true в контексте условия), если фактическое имя языка из входных данных (сохраненное в act) совпадает с указанным именем целевого языка. указывается в командной строке (сохраняется в tgt) и 0 (false) в противном случае. Когда этот флаг f равен 1 (истина), он вызывает действие awks по умолчанию для печати текущей строки ввода. 1-й сценарий - это просто более простая версия того же самого, поскольку ему не нужно удалять (...).

Поскольку вышеупомянутое сравнение выполняет сравнение строк (в отличие от сравнения регулярных выражений, которое может потребоваться by sed) он будет работать как есть для любого имени языка, которое не содержит ' или backsla sh (FWIW Я не знаю никаких имен языков программирования, которые содержат то и другое, и я не вижу никаких на https://en.wikipedia.org/wiki/List_of_programming_languages). Если это проблема, код можно настроить так, чтобы он соответствовал ...

1 голос
/ 08 мая 2020

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

sed -n '/^([^)]\+)/h;//b;G;/^(Python)/MP' file

Отключите неявную печать с помощью параметра -n.

Скопируйте разделитель в удерживаемое пространство (HS) .

Для любой другой строки добавьте строку-разделитель.

Если текущая строка содержит требуемый разделитель, то есть язык, напечатайте первую строку в пространстве шаблона.

NB Флаг M позволяет регулярному выражению соответствовать точному разделителю и определяется GNU c.

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

sed -n '/^([^)]\+)/h;G;/^(Python)/MP' file

Чтобы удалить разделитель из первой строки, используйте:

sed -n '/^([^)]\+)\s*/h;//s///;G;/^(Python)/MP' file

В общих чертах: строка, содержащая разделитель (Python), (Sage) или любой другой (...), сохраняется в другом буфере, называемом удержанием пространство (HS). HS добавляется к каждой строке. Если вторая строка соответствует предполагаемому разделителю, первая строка печатается P. Поскольку была активирована опция -n, любые строки, не соответствующие вышеуказанным критериям, будут забыты.

0 голосов
/ 08 мая 2020

Просто выводите только то, что grep соответствует, а не всю строку.

<file tr '\n' '@' | grep -o '@(Python).*@([A-Z].*)' | tr '@' '\n

При фильтрации странных входов я иногда (ab-) использую sed -z:

sed -z 's/.*\(\n(Python).*\n([A-Z].*)[^\n]*\n\).*/\1/' file

Вы можете заинтересоваться, как фильтровать строки между шаблонами в bash.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...