awk, sed 또는 기타 텍스트 처리 제안


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 등일 수 있다는 것입니다. 이는 정보를 이동시키는 유일한 방법입니다. 괄호 안의 숫자는 항상 동일하며, 알파벳 문자 만 관련 번호와 함께 확장해야합니다.

그래서 숫자와 알파벳을 연관시키는 것은 필요합니다.

이것은 나에게 마음을 굽히는 것처럼 보입니다. 어떤 도움을 많이 주셨습니다. 그건 그렇고 새로운 것입니다.


성능에 민감합니까? for 루프를 사용한 쉬운 솔루션은 그리 빠르지 않을 것입니다.
Eugen Rieck

답변:


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 사이에 무엇을 복용하여 (), 공백 무시
  • STARTEND 대시로 구분되며 공백은 무시됩니다.
  • 번호와 문자는 첫 번째 문자와 두 번째 문자로 분리됩니다.

sed 표현식의 분석은 환상적 일 것이고, 일부 하위 표현식처럼 보이며, \s 그게 ...?
Xen2050

@ Xen2050 \s 관련 부분 주위의 공백을 무시하거나 올바르게 처리해야합니다. 다른 모든 것은 아주 자명하다.
Eugen Rieck

1
나는 "awk, sed, 또는 근본적으로 무엇이든"을 찾는 누군가에게 자기 설명하는 것을 믿지 않을 것입니다. 모든 힌트가 +1을 돕습니다.
Xen2050

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

(와 shksh 출력은 동일 함)


1

펄 방식 :

#!/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"

위대한 솔루션을 제공 해주신 모든 분들께 감사드립니다. 나는 관용과 전문성에 정말 두려움을 느낍니다. 그것은 작동합니다! 나는 sed가 너무 강력하다는 것을 몰랐다. 이제이 특정 패턴과 일치하지 않는 항목을 전달하는 방법을 알아야합니다. 고맙습니다. 새해 복 많이 받으세요 !!
jeffschips

@jeffschips : 환영합니다. 대답 중 하나를 받아 들일 수 있음을 자유롭게 표명 해주십시오. superuser.com/help/someone-answers
Toto

0

루핑을 필요로하지 않고 sed에 4 번의 호출만을 사용하는 버전. 맹세 해, 나의 버전은 2 개의 수 치가 동등하다는 것을 검사하지 않는다. 사실, 두 번째 것은 무시되고 심지어 생략 될 수 있습니다. "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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.