1

У меня есть следующий повторяющийся образец текста, который необходимо переформатировать.

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

Лучше всего приведу пример:

"Gene Code (1A - 1F) D2 fragment, D74F"

Мне нужно, чтобы конечный продукт выглядел так:

Gene Code, 1A, D2 fragment, D74F
Gene Code, 1B, D2 fragment, D74F
Gene Code, 1C, D2 fragment, D74F
Gene Code, 1D, D2 fragment, D74F
Gene Code, 1E, D2 fragment, D74F
Gene Code, 1F, D2 fragment, D74F

Загвоздка в том, что исходная строка, содержащаяся в скобках, может быть чем-то вроде 1A-1F или 3D-3H и т.д. Это единственные сдвигающиеся биты информации. Числа в круглых скобках всегда одинаковы, только буквенные буквы нуждаются в расширении с их соответствующим номером.

Поэтому необходимо каким-то образом соотнести алфавит с числами.

Для меня это похоже на умопомрачение. Любая помощь высоко ценится. Новичок в этом, кстати.

4 ответа4

2

Это скрипт bash

#!/bin/bash

PART1=$(echo "$1" | sed 's/\(.*\)\s(.*/\1/')
PART3=$(echo "$1" | sed 's/.*)\(.*\)/\1/')
PART2=$(echo "$1" | sed 's/.*(\s*\(.*\)).*/\1/')

START=$(echo "$PART2" | sed 's/\s*-.*//')
END=$(echo "$PART2" | sed 's/.*-\s*//')

STARTNUM=$(echo "$START" | sed 's/^\(.\).*/\1/')
ENDNUM=$(echo "$END" | sed 's/^\(.\).*/\1/')
if test "$STARTNUM" '!=' "$ENDNUM"; then
    echo "Error: Numeral is different"
    exit 1
fi

STARTLETTER=$(echo "$START" | sed 's/^.\(.\).*/\1/')
ENDLETTER=$(echo "$END" | sed 's/^.\(.\).*/\1/')

OUTPUT=''
for LETTER in A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ; do
    test "$LETTER" '==' "$STARTLETTER" && OUTPUT='yes'
    test -n "$OUTPUT" && echo "$PART1, $STARTNUM$LETTER,$PART3"
    test "$LETTER" '==' "$ENDLETTER" && OUTPUT=''
done

Будет делать то, что вам нужно, хотя и не очень эффективно, когда вызывается с оригинальным текстом как $1

РЕДАКТИРОВАТЬ

Как просил несколько слов о выражениях sed :

  • Я изолирую PART1 , беря все до пробела и открытия (
  • Я изолирую PART3 , взяв все от закрытия )
  • Я изолирую PART2 , беря то, что находится между ( и ) , игнорируя пробелы
  • START и END изолированы чертой, снова игнорируя пробелы
  • Число и буква изолированы, будучи первым и вторым символом
1

Если доступен GNU sed

sed -r 's/([^(]+) \((.)(.) - .(.)\)(.*)/printf \x27\1, \2%s,\5\\n\x27 {\3..\4}/e' <<<'Gene Code (1A - 1F) D2 fragment, D74F'
Gene Code, 1A, D2 fragment, D74F
Gene Code, 1B, D2 fragment, D74F
Gene Code, 1C, D2 fragment, D74F
Gene Code, 1D, D2 fragment, D74F
Gene Code, 1E, D2 fragment, D74F
Gene Code, 1F, D2 fragment, D74F

Если нет, запустите его, отправив как трубу в оболочку

sed -r 's/([^(]+) \((.)(.) - .(.)\)(.*)/printf \x27\1, \2%s,\5\\n\x27 {\3..\4}/' <<<'Gene Code (1A - 1F) D2 fragment, D74F'|bash
Gene Code, 1A, D2 fragment, D74F
Gene Code, 1B, D2 fragment, D74F
Gene Code, 1C, D2 fragment, D74F
Gene Code, 1D, D2 fragment, D74F
Gene Code, 1E, D2 fragment, D74F
Gene Code, 1F, D2 fragment, D74F

sh и ksh вывод одинаковый)

1

Perl способ:

#!/usr/bin/perl
use feature 'say';

my $str = '"Gene Code (3D - 3H) D2 fragment, D74F"';
# get begin number, begin letter, end number, end letter
my ($bn,$bl,$en,$el) = $str =~ /\((.)(.) - (.)(.)\)/;
# loop from begin letter to end letter
for my $i ($bl .. $el) {
    # do the substitution and print
    ($_ = $str) =~ s/ \(.. - ..\)/, $bn$i,/ && say;
}

Выход:

"Gene Code, 3D, D2 fragment, D74F"
"Gene Code, 3E, D2 fragment, D74F"
"Gene Code, 3F, D2 fragment, D74F"
"Gene Code, 3G, D2 fragment, D74F"
"Gene Code, 3H, D2 fragment, D74F"
0

Версия, которая не требует зацикливания и использует только четыре вызова sed. Конечно, моя версия не проверяет, что два числа равны. Фактически, второй игнорируется и может даже быть опущен, как с "Gene Code (91K - Q) D2 fragment, D74F" . Также нижняя граница и высокая граница могут появляться в любом порядке. Если нижняя граница больше верхней границы, то выходная последовательность меняется на противоположную.

$ cat foo
#!/usr/bin/env bash

# Script to expand $1 passed as:

# "Gene Code (91K - 91Q) D2 fragment, D74F"
# 
# into the output:
# 
# Gene Code, 91K, D2 fragment, D74F
# Gene Code, 91L, D2 fragment, D74F
# Gene Code, 91M, D2 fragment, D74F
# Gene Code, 91N, D2 fragment, D74F
# Gene Code, 91O, D2 fragment, D74F
# Gene Code, 91P, D2 fragment, D74F
# Gene Code, 91Q, D2 fragment, D74F


# Copy $1 into FMT_STRING, replacing the " (91K - 91Q)" bit with a ', %s,' 
# printf directive, such as 'Gene Code, %s, D2 fragment, D74F':

FMT_STRING="$(sed -e 's/ (.* - .*)/, %s,/' <<< "$1")"

# Parse the beginning and ending bounds and format them with just a 
# space between, such as '91K 91Q':

BOUNDS="$(sed -e 's/^[^(]*(\(.*\) - \(.*\)) .*/\1 \2/' <<< "$1")"

# Extract the (first) static numeric part from BOUNDS, e.g. '91'

NUMERIC="$(sed -e 's/[^0-9].*//' <<< "$BOUNDS")"

# remove all digits [0-9] from BOUNDS, e.g. 'K Q'
BOUNDS="$(sed -e 's/[0-9]//g' <<< "$BOUNDS")"

FMT_STRING="$(printf "$FMT_STRING" "${NUMERIC}%c")"

jot -w "$FMT_STRING" - $BOUNDS

Образец вывода:

$ ./foo "Gene Code (737L - 737X) D2 fragment, D74F"
Gene Code, 737L, D2 fragment, D74F
Gene Code, 737M, D2 fragment, D74F
Gene Code, 737N, D2 fragment, D74F
Gene Code, 737O, D2 fragment, D74F
Gene Code, 737P, D2 fragment, D74F
Gene Code, 737Q, D2 fragment, D74F
Gene Code, 737R, D2 fragment, D74F
Gene Code, 737S, D2 fragment, D74F
Gene Code, 737T, D2 fragment, D74F
Gene Code, 737U, D2 fragment, D74F
Gene Code, 737V, D2 fragment, D74F
Gene Code, 737W, D2 fragment, D74F
Gene Code, 737X, D2 fragment, D74F

Реверсирование границ меняет вывод:

$ ./foo "Gene Code (737X - 737L) D2 fragment, D74F"
Gene Code, 737X, D2 fragment, D74F
Gene Code, 737W, D2 fragment, D74F
Gene Code, 737V, D2 fragment, D74F
Gene Code, 737U, D2 fragment, D74F
Gene Code, 737T, D2 fragment, D74F
Gene Code, 737S, D2 fragment, D74F
Gene Code, 737R, D2 fragment, D74F
Gene Code, 737Q, D2 fragment, D74F
Gene Code, 737P, D2 fragment, D74F
Gene Code, 737O, D2 fragment, D74F
Gene Code, 737N, D2 fragment, D74F
Gene Code, 737M, D2 fragment, D74F
Gene Code, 737L, D2 fragment, D74F

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .