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

Вы можете использовать GhostScript для пакетного вывода .ai в различных форматах, т. е. прозрачный PNG:

gs -dNOPAUSE -dBATCH -sDEVICE=pngalpha -r300 -sOutputFile=out.png in.ai

Где -r300 разрешение dpi.

Для доступных устройств, с которыми вы можете конвертировать формат .ai, справочную документацию.

6
задан 4 April 2018 в 19:31

18 ответов

Использование awk:

$ awk '!seen{match($0, /A.*B/);seen=1;next} {print substr($0,RSTART,RLENGTH);seen=0}' infile
7890MNOP
34567890MNOPQRST

Объяснение: прочитайте man awk:

RSTART
          The index of the first character matched by match(); 0 if no
          match.  (This implies that character indices start at one.)

RLENGTH
          The length of the string matched by match(); -1 if no match.

match(s, r [, a])  
          Return the position in s where the regular expression r occurs, 
          or 0 if r is not present, and set the values of RSTART and RLENGTH. (...)

substr(s, i [, n])
          Return the at most n-character substring of s starting at I.
          If n is omitted, use the rest of s.
8
ответ дан 22 May 2018 в 11:36

Использование awk:

$ awk '!seen{match($0, /A.*B/);seen=1;next} {print substr($0,RSTART,RLENGTH);seen=0}' infile 7890MNOP 34567890MNOPQRST

Объяснение: прочитайте man awk:

RSTART The index of the first character matched by match(); 0 if no match. (This implies that character indices start at one.) RLENGTH The length of the string matched by match(); -1 if no match. match(s, r [, a]) Return the position in s where the regular expression r occurs, or 0 if r is not present, and set the values of RSTART and RLENGTH. (...) substr(s, i [, n]) Return the at most n-character substring of s starting at I. If n is omitted, use the rest of s.
8
ответ дан 17 July 2018 в 17:29

Использование awk:

$ awk '!seen{match($0, /A.*B/);seen=1;next} {print substr($0,RSTART,RLENGTH);seen=0}' infile 7890MNOP 34567890MNOPQRST

Объяснение: прочитайте man awk:

RSTART The index of the first character matched by match(); 0 if no match. (This implies that character indices start at one.) RLENGTH The length of the string matched by match(); -1 if no match. match(s, r [, a]) Return the position in s where the regular expression r occurs, or 0 if r is not present, and set the values of RSTART and RLENGTH. (...) substr(s, i [, n]) Return the at most n-character substring of s starting at I. If n is omitted, use the rest of s.
8
ответ дан 23 July 2018 в 18:18

Поскольку вы упомянули sed, вы можете сделать это с помощью сценария sed:

/^x*Ax*Bx*$/{              # If an index line is matched, then
  N                        # append the next (content) line into the pattern buffer
  :a                       # label a
  s/^x(.*\n).(.*)/\1\2/    # remove "x" from the index line start and a char from the content line start
  ta                       # if a subtitution happened in the previous line then jump back to a
  :b                       # label a
  s/(.*)x(\n.*).$/\1\2/    # remove "x" from the index line end and a char from the content line end
  tb                       # if a subtitution happened in the previous line then jump back to b
  s/.*\n//                 # remove the index line
}

Если вы поместите это все в одну командную строку, это выглядит так:

$ sed -r '/^x*Ax*Bx*$/{N;:a;s/^x(.*\n).(.*)/\1\2/;ta;:b;s/(.*)x(\n.*).$/\1\2/;tb;s/.*\n//;}' example-file.txt
7890MNOP
34567890MNOPQRST
$ 

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

FWIW, я не думаю, что это можно было бы сделать чисто с grep, хотя я был бы счастлив оказаться ошибочным.

7
ответ дан 22 May 2018 в 11:36

Хотя вы можете сделать это с помощью AWK, я предлагаю Perl. Вот сценарий:

#!/usr/bin/env perl

use strict;
use warnings;

while (my $pattern = <>) {
    my $text = <>;
    my $start = index $pattern, 'A';
    my $stop = index $pattern, 'B', $start;
    print substr($text, $start, $stop - $start + 1), "\n";
}

Вы можете назвать этот файл сценария так, как вам нравится. Если вы хотите назвать его interval и поместить в текущий каталог, вы можете пометить его исполняемым файлом chmod +x interval. Затем вы можете запустить:

./interval paths...

Заменить paths... на фактическое имя пути или пути к файлам, которые вы хотите проанализировать. Например:

$ ./interval interval-example.txt
7890MNOP
34567890MNOPQRST

Способ работы сценария заключается в том, что до тех пор, пока не будет достигнут конец ввода (т. Е. Больше строк), он:

Читает строку, , который является вашей строкой с A и B, а другой - $text, которая является строкой, которая будет нарезана. Находит индекс первого A в $pattern и первый B, кроме тех, которые могут предшествовать этому первому A, и сохраняет их в переменных $start и $stop, соответственно. Вырезает только часть $text, индексы которой варьируются от $start до $stop. Функция substr Perl принимает аргументы смещения и длины, что является причиной вычитания, и вы включаете письмо сразу под B, что является причиной добавления 1. Печатает именно эту часть, за которой следует разрыв строки.

Если по какой-то причине вы предпочтете короткую однострочную команду, которая выполняет одно и то же, но легко вставлена, но также сложнее понять и поддерживать - тогда вы можете использовать это: [ ! d10]

perl -wple '$i=index $_,"A"; $_=substr <>,$i,index($_,"B",$i)-$i+1' paths...

(Как и раньше, вы должны заменить paths... на фактические пути.)

7
ответ дан 22 May 2018 в 11:36

Вот как это сделать в GNU awk:

$ gawk 'NR%2 {split($0,a,/[AB]/); FIELDWIDTHS = length(a[1])" "length(a[2])+2; next} {print $2}' file
7890MNOP
34567890MNOPQRST
3
ответ дан 22 May 2018 в 11:36

Мы не знаем наверняка, если ..

могут быть линии между парами или перед ними, которые не являются частью пары; заголовок? объяснение? комментарий? первая строка начинается с x по определению, вторая строка пары, возможно, начинается с x

. Чтобы поймать все эти ситуации, используя set(), мы можем искать линии, которые существуют только of (all) x, A, B. Эти, мы можем быть положительными, являются первыми линиями наших пар.

Таким образом, мы получаем в python:

#!/usr/bin/env python3

f = "/path/to/file"

printresult = False

for l in open(f):
    if printresult == True:
        print(l[i[0]:i[1]])
        printresult = False
    elif set(l.strip()) == {"A", "x", "B"}:
        i = [l.index("A"), l.index("B") + 1]
        printresult = True

Таким образом, вывод:

будет:

7890MNOP
34567890MNOPQRST
x234567890MNOPQR
3
ответ дан 22 May 2018 в 11:36

С очень простым синтаксисом Python 3 мы можем сделать следующий скрипт:

#!/usr/bin/env python3
import sys

for fname in sys.argv[1:]:
    with open(fname) as fd:
        for line in fd:
            if line.startswith('x'):
                start_index = line.find('A')
                end_index = line.rfind('B')
            else:
                print(line[start_index:end_index+1])

Что работает так:

$ ./croplines.py  input.txt 
7890MNOP
34567890MNOPQRST

OP предоставил MCVE, но didn ' t предоставляют другие требования, поэтому, основываясь на том, что они показывают, у нас есть чередующийся шаблон: первая строка, начинающаяся с «x», затем строка с данными (в данном случае числовая, но это не имеет значения для нашей цели). [!d2 ]

Преимущества этого подхода:

простой / читаемый синтаксис и легко поддерживать отсутствие необходимости беспокоиться о соответствии POSIX, если нам нужно что-то, что масштабируется до нескольких файлов и сокращает операторы командной строки - мы уже есть for fname in sys.argv[1:], и мы могли бы даже добавить дополнительную гибкость в определении шаблонов в командной строке; мы можем добавить рекурсивную опцию с модулем os.walk, если мы хотим / нуждаемся, если нам нужно безоговорочно напечатать следующую строку (и, таким образом, игнорировать строки, которые не соответствуют шаблону), мы могли бы использовать только fd.readline()
    #!/usr/bin/env python3

    import sys

    for fname in sys.argv[1:]:
        with open(fname) as fd:
            for line in fd:

                start_index = 0
                end_index = len(line)-1

                if line.startswith('x'):
                    start_index = line.find('A')
                    end_index = line.rfind('B')+1
                    line = fd.readline()
                    print(line[start_index:end_index])
3
ответ дан 22 May 2018 в 11:36

Хотя вы можете сделать это с помощью AWK, я предлагаю Perl. Вот сценарий:

#!/usr/bin/env perl use strict; use warnings; while (my $pattern = <>) { my $text = <>; my $start = index $pattern, 'A'; my $stop = index $pattern, 'B', $start; print substr($text, $start, $stop - $start + 1), "\n"; }

Вы можете назвать этот файл сценария так, как вам нравится. Если вы хотите назвать его interval и поместить в текущий каталог, вы можете пометить его исполняемым файлом chmod +x interval. Затем вы можете запустить:

./interval paths...

Заменить paths... на фактическое имя пути или пути к файлам, которые вы хотите проанализировать. Например:

$ ./interval interval-example.txt 7890MNOP 34567890MNOPQRST

Способ работы сценария заключается в том, что до тех пор, пока не будет достигнут конец ввода (т. Е. Больше строк), он:

Читает строку, $pattern, который является вашей строкой с A и B, а другой - $text, которая является строкой, которая будет нарезана. Находит индекс первого A в $pattern и первый B, кроме тех, которые могут предшествовать этому первому A, и сохраняет их в переменных $start и $stop, соответственно. Вырезает только часть $text, индексы которой варьируются от $start до $stop. Функция substr Perl принимает аргументы смещения и длины, что является причиной вычитания, и вы включаете письмо сразу под B, что является причиной добавления 1. Печатает именно эту часть, за которой следует разрыв строки.

Если по какой-то причине вы предпочтете короткую однострочную команду, которая выполняет одно и то же, но легко вставлена, но также сложнее понять и поддерживать - тогда вы можете использовать это: [ ! d10] perl -wple '$i=index $_,"A"; $_=substr <>,$i,index($_,"B",$i)-$i+1' paths...

(Как и раньше, вы должны заменить paths... на фактические пути.)

7
ответ дан 17 July 2018 в 17:29

Мы не знаем наверняка, если ..

могут быть линии между парами или перед ними, которые не являются частью пары; заголовок? объяснение? комментарий? первая строка начинается с x по определению, вторая строка пары, возможно, начинается с x

. Чтобы поймать все эти ситуации, используя set(), мы можем искать линии, которые существуют только of (all) x, A, B. Эти, мы можем быть положительными, являются первыми линиями наших пар.

Таким образом, мы получаем в python:

#!/usr/bin/env python3 f = "/path/to/file" printresult = False for l in open(f): if printresult == True: print(l[i[0]:i[1]]) printresult = False elif set(l.strip()) == {"A", "x", "B"}: i = [l.index("A"), l.index("B") + 1] printresult = True

Таким образом, вывод:

Some results of whatever test ----------------------------- xxxxxxAxxxxxxBxxxxxx 1234567890MNOPQRSTUV blub or blublub xxAxxxxxxxxxxxxxxBxxxxxx 1234567890MNOPQRSTUVWXYZ peanutbutter AxxxxxxxxxxxxxxBxxxxxx x234567890MNOPQRSTUVWXYZ

будет:

7890MNOP 34567890MNOPQRST x234567890MNOPQR
3
ответ дан 17 July 2018 в 17:29

Поскольку вы упомянули sed, вы можете сделать это с помощью сценария sed:

/^x*Ax*Bx*$/{ # If an index line is matched, then N # append the next (content) line into the pattern buffer :a # label a s/^x(.*\n).(.*)/\1\2/ # remove "x" from the index line start and a char from the content line start ta # if a subtitution happened in the previous line then jump back to a :b # label a s/(.*)x(\n.*).$/\1\2/ # remove "x" from the index line end and a char from the content line end tb # if a subtitution happened in the previous line then jump back to b s/.*\n// # remove the index line }

Если вы поместите это все в одну командную строку, это выглядит так:

$ sed -r '/^x*Ax*Bx*$/{N;:a;s/^x(.*\n).(.*)/\1\2/;ta;:b;s/(.*)x(\n.*).$/\1\2/;tb;s/.*\n//;}' example-file.txt 7890MNOP 34567890MNOPQRST $

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

FWIW, я не думаю, что это можно было бы сделать чисто с grep, хотя я был бы счастлив оказаться ошибочным.

7
ответ дан 17 July 2018 в 17:29

С очень простым синтаксисом Python 3 мы можем сделать следующий скрипт:

#!/usr/bin/env python3 import sys for fname in sys.argv[1:]: with open(fname) as fd: for line in fd: if line.startswith('x'): start_index = line.find('A') end_index = line.rfind('B') else: print(line[start_index:end_index+1])

Что работает так:

$ ./croplines.py input.txt 7890MNOP 34567890MNOPQRST

OP предоставил MCVE, но didn ' t предоставляют другие требования, поэтому, основываясь на том, что они показывают, у нас есть чередующийся шаблон: первая строка, начинающаяся с «x», затем строка с данными (в данном случае числовая, но это не имеет значения для нашей цели).

Преимущества этого подхода:

простой / читаемый синтаксис и легко поддерживать отсутствие необходимости беспокоиться о соответствии POSIX, если нам нужно что-то, что масштабируется до нескольких файлов и сокращает операторы командной строки - мы уже есть for fname in sys.argv[1:], и мы могли бы даже добавить дополнительную гибкость в определении шаблонов в командной строке; мы можем добавить рекурсивную опцию с модулем os.walk, если мы хотим / нуждаемся, если нам нужно безоговорочно напечатать следующую строку (и, таким образом, игнорировать строки, которые не соответствуют шаблону), мы могли бы использовать только fd.readline() #!/usr/bin/env python3 import sys for fname in sys.argv[1:]: with open(fname) as fd: for line in fd: start_index = 0 end_index = len(line)-1 if line.startswith('x'): start_index = line.find('A') end_index = line.rfind('B')+1 line = fd.readline() print(line[start_index:end_index])
3
ответ дан 17 July 2018 в 17:29

Вот как это сделать в GNU awk:

$ gawk 'NR%2 {split($0,a,/[AB]/); FIELDWIDTHS = length(a[1])" "length(a[2])+2; next} {print $2}' file 7890MNOP 34567890MNOPQRST
3
ответ дан 17 July 2018 в 17:29

Хотя вы можете сделать это с помощью AWK, я предлагаю Perl. Вот сценарий:

#!/usr/bin/env perl use strict; use warnings; while (my $pattern = <>) { my $text = <>; my $start = index $pattern, 'A'; my $stop = index $pattern, 'B', $start; print substr($text, $start, $stop - $start + 1), "\n"; }

Вы можете назвать этот файл сценария так, как вам нравится. Если вы хотите назвать его interval и поместить в текущий каталог, вы можете пометить его исполняемым файлом chmod +x interval. Затем вы можете запустить:

./interval paths...

Заменить paths... на фактическое имя пути или пути к файлам, которые вы хотите проанализировать. Например:

$ ./interval interval-example.txt 7890MNOP 34567890MNOPQRST

Способ работы сценария заключается в том, что до тех пор, пока не будет достигнут конец ввода (т. Е. Больше строк), он:

Читает строку, $pattern, который является вашей строкой с A и B, а другой - $text, которая является строкой, которая будет нарезана. Находит индекс первого A в $pattern и первый B, кроме тех, которые могут предшествовать этому первому A, и сохраняет их в переменных $start и $stop, соответственно. Вырезает только часть $text, индексы которой варьируются от $start до $stop. Функция substr Perl принимает аргументы смещения и длины, что является причиной вычитания, и вы включаете письмо сразу под B, что является причиной добавления 1. Печатает именно эту часть, за которой следует разрыв строки.

Если по какой-то причине вы предпочтете короткую однострочную команду, которая выполняет одно и то же, но легко вставлена, но также сложнее понять и поддерживать - тогда вы можете использовать это: [ ! d10] perl -wple '$i=index $_,"A"; $_=substr <>,$i,index($_,"B",$i)-$i+1' paths...

(Как и раньше, вы должны заменить paths... на фактические пути.)

7
ответ дан 23 July 2018 в 18:18

Мы не знаем наверняка, если ..

могут быть линии между парами или перед ними, которые не являются частью пары; заголовок? объяснение? комментарий? первая строка начинается с x по определению, вторая строка пары, возможно, начинается с x

. Чтобы поймать все эти ситуации, используя set(), мы можем искать линии, которые существуют только of (all) x, A, B. Эти, мы можем быть положительными, являются первыми линиями наших пар.

Таким образом, мы получаем в python:

#!/usr/bin/env python3 f = "/path/to/file" printresult = False for l in open(f): if printresult == True: print(l[i[0]:i[1]]) printresult = False elif set(l.strip()) == {"A", "x", "B"}: i = [l.index("A"), l.index("B") + 1] printresult = True

Таким образом, вывод:

Some results of whatever test ----------------------------- xxxxxxAxxxxxxBxxxxxx 1234567890MNOPQRSTUV blub or blublub xxAxxxxxxxxxxxxxxBxxxxxx 1234567890MNOPQRSTUVWXYZ peanutbutter AxxxxxxxxxxxxxxBxxxxxx x234567890MNOPQRSTUVWXYZ

будет:

7890MNOP 34567890MNOPQRST x234567890MNOPQR
3
ответ дан 23 July 2018 в 18:18

Поскольку вы упомянули sed, вы можете сделать это с помощью сценария sed:

/^x*Ax*Bx*$/{ # If an index line is matched, then N # append the next (content) line into the pattern buffer :a # label a s/^x(.*\n).(.*)/\1\2/ # remove "x" from the index line start and a char from the content line start ta # if a subtitution happened in the previous line then jump back to a :b # label a s/(.*)x(\n.*).$/\1\2/ # remove "x" from the index line end and a char from the content line end tb # if a subtitution happened in the previous line then jump back to b s/.*\n// # remove the index line }

Если вы поместите это все в одну командную строку, это выглядит так:

$ sed -r '/^x*Ax*Bx*$/{N;:a;s/^x(.*\n).(.*)/\1\2/;ta;:b;s/(.*)x(\n.*).$/\1\2/;tb;s/.*\n//;}' example-file.txt 7890MNOP 34567890MNOPQRST $

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

FWIW, я не думаю, что это можно было бы сделать чисто с grep, хотя я был бы счастлив оказаться ошибочным.

7
ответ дан 23 July 2018 в 18:18

С очень простым синтаксисом Python 3 мы можем сделать следующий скрипт:

#!/usr/bin/env python3 import sys for fname in sys.argv[1:]: with open(fname) as fd: for line in fd: if line.startswith('x'): start_index = line.find('A') end_index = line.rfind('B') else: print(line[start_index:end_index+1])

Что работает так:

$ ./croplines.py input.txt 7890MNOP 34567890MNOPQRST

OP предоставил MCVE, но didn ' t предоставляют другие требования, поэтому, основываясь на том, что они показывают, у нас есть чередующийся шаблон: первая строка, начинающаяся с «x», затем строка с данными (в данном случае числовая, но это не имеет значения для нашей цели).

Преимущества этого подхода:

простой / читаемый синтаксис и легко поддерживать отсутствие необходимости беспокоиться о соответствии POSIX, если нам нужно что-то, что масштабируется до нескольких файлов и сокращает операторы командной строки - мы уже есть for fname in sys.argv[1:], и мы могли бы даже добавить дополнительную гибкость в определении шаблонов в командной строке; мы можем добавить рекурсивную опцию с модулем os.walk, если мы хотим / нуждаемся, если нам нужно безоговорочно напечатать следующую строку (и, таким образом, игнорировать строки, которые не соответствуют шаблону), мы могли бы использовать только fd.readline() #!/usr/bin/env python3 import sys for fname in sys.argv[1:]: with open(fname) as fd: for line in fd: start_index = 0 end_index = len(line)-1 if line.startswith('x'): start_index = line.find('A') end_index = line.rfind('B')+1 line = fd.readline() print(line[start_index:end_index])
3
ответ дан 23 July 2018 в 18:18

Вот как это сделать в GNU awk:

$ gawk 'NR%2 {split($0,a,/[AB]/); FIELDWIDTHS = length(a[1])" "length(a[2])+2; next} {print $2}' file 7890MNOP 34567890MNOPQRST
3
ответ дан 23 July 2018 в 18:18

Другие вопросы по тегам:

Похожие вопросы: