탭으로 구분된 파일 열의 텍스트 문자열에서 첫 번째 정수를 추출하는 방법은 무엇입니까?

탭으로 구분된 파일 열의 텍스트 문자열에서 첫 번째 정수를 추출하는 방법은 무엇입니까?

나는 의료 유전학 분야에서 일하고 있으며 종종 열 중 하나(예: 열 5)에 텍스트 문자열이 있는 구분된 텍스트 파일을 가지고 있습니다. 우리 전문 용어로는 "돌연변이" 입니다
c.2458C>T. c.45_46delAAc.749_754delinsTG

마찬가지로 다른 파일에서는 다음과 같이 읽을 수 있습니다.
p.Glu34*또는 p.Ala78_Arg80del또는p.L378Ffs*11

및 이 있어야 하지만 생략될 수도 있습니다 c.. p.숫자가 아닌 문자는 얼마든지 있을 수 있습니다. 이 숫자는 항상 정수이며 일반적으로 길이가 약 1-14입니다.

내 파일 어딘가에 새 열을 추가하고 싶습니다.첫 번째만첫 번째 예에서는 2458, 45, 749와 같은 정수입니다. 그런 다음 이 정수를 키 값으로 사용하여 조회 테이블에서 여러 값을 조회하려고 합니다.

내 파일 중 일부에는 70,000줄이 있어서 수동으로 편집할 수 없습니다...

해결책은 기본적일수록 좋습니다. bash, sed 또는 awk를 사용하여 수행할 수 있나요?

예시 테이블은 다음과 같습니다(올바른 설명은 다음과 같습니다).

1       2       3       4       c.2458C>T
a   b   c   d   c.45_46delAA
a1  b2  c3  d4  p.Ala78_Arg80del

(참고: 열은 공백이 아닌 탭으로 구분됩니다.)

형식에는 사양이 있습니다.인간 게놈 변이 컨소시엄. 어떤 프로그램도 이 형식을 사용하지 않지만(희망합니다!) 사람들은 출판물과 의료 보고서에 이 형식을 사용합니다. 다음과 같은 최신 형식다양한 호출 형식도입되었으므로 구문 분석하기가 더 쉽습니다.

답변1

설명에 따라 탭으로 구분된 파일을 입력으로 가정합니다. 예:

$ cat file
1       2       3       4       c.2458C>T       6
a       b       c       d       c.45_46delAA or f
a1      b2      c3      d4      p.Ala78_Arg80del        f6

sed 사용

다섯 번째 열의 첫 번째 정수를 찾으려면 다음을 수행하세요.

$ sed -r 's/([^\t]*\t){4}[^[:digit:]]*([[:digit:]]+).*/\2/' file
2458
45
78

위의 내용은 GNU에서 테스트되었습니다 sed. OSX 또는 기타 BSD 시스템의 경우 다음을 시도하십시오.

sed -E 's/([^\t]*\t){4}[^[:digit:]]*([[:digit:]][[:digit:]]*).*/\2/' file

awk를 사용하세요

$ awk '{sub(/^[^[:digit:]]*/, "", $5); sub(/[^[:digit:]].*/, "", $5); print $5;}' file
2458
45
78

답변2

@ John1024의 예제 텍스트를 사용하면 이는 GNU-awk에만 해당됩니다.

gawk -F '\t' -v OFS='\t' 'match($5, /[[:digit:]]+/, m) {$(++NF) = m[0]} 1' file

생산하다

1   2   3   4   c.2458C>T   6   2458
a   b   c   d   c.45_46delAA    or  f   45
a1  b2  c3  d4  p.Ala78_Arg80del    f6  78

아니면 펄

perl -F'\t' -lane 'print join "\t", @F, $F[4]=~/(\d+)/' file

답변3

Glenn jackman의 GNU/AWK 답변은 우아하지만 더 간단합니다.

awk 'BEGIN {FS=OFS="\t"} match($5,/[0-9]+/,arr) {print $0,arr[0]}' file

답변4

발생으로 대체 할 sed수 있으므로 다섯 번째 항목만 필요합니다.\t<ab>- 분리된[1]다른 가능한 일치 항목을 제외하여 필드와 그 안의 모든 숫자:

sed 's/[^\t0-9]*\([0-9]*\)[^\t]*/\1/5' <infile

다른 예제를 클립보드에 복사한 후 다음을 수행했습니다.

xsel -bo | unexpand -a | sed ...

... unexpand -a통행료<탭>실제 크기로 변환된 공간 순서<탭>. 그리고 그걸 프린트해서...

1   2   3   4   2458    6
a   b   c   d   45
a1  b2  c3  d4  78  f6

...5번째 열의 첫 번째 정수만 분리합니다. 하지만 이것이 당신이 원하는 것인지 확실하지 않습니다. 한 줄의 다섯 번째 열에 있는 첫 번째 정수만 원한다면 훨씬 쉽습니다.(그리고 더 빠르게).

<infile \
 cut -f5 | tr -cs '0-9\n' \\t |
 expand -t1,2,4 | cut -d' ' -f-2

...첫 번째 cut는 다섯 번째입니다.<탭>- 분리된[2]행당 완전한 데이터 필드(필드당 여러 정수를 사용하여 발생할 수 있는 문제를 방지하기 위해)그런 tr다음<탭> Ewlines 세트를 보완하는 각 -s압축 문자 시퀀스 및-c\n0-9 표준 번호 [삼].

이는 출력에서 ​​첫 번째 정수가 첫 번째 또는 두 번째 필드에 있음을 의미합니다. 첫 번째 필드가 이제 비어 있기 때문입니다.(<탭>에 의해 시작됨)또는 기억하는 대로 접두사가 붙어 있는지 여부에 따라 일련의 숫자를 사용합니다. 그래서 나의 expand첫 번째와 두 번째 CD<탭>-한 칸, 세 번째 칸 위치에서 줄에서 중지 - 공백으로 구분된 필드 목록을 빈 첫 번째 필드 또는 빈 세 번째 필드로 효과적으로 채웁니다. 여기에서 cut처음 두 필드를 직접 출력할 수 있습니다.

 2458
 45
 78

...내가 사용한 예제에 대한 결과는 다음과 같습니다. 모두 다음과 같이 만들어졌기 때문입니다.[cp].그러니 모두가 리드를 갖고 있지<탭>그러나 그렇지 않은 사람들은 비틀거리며 떠날 것입니다. 또는 각 정수를 공백으로 구분하여 모든 결과를 한 줄로 압축하려면 |xargs명령에 추가하고 다음을 얻을 수 있습니다.

2458 45 78

노트

  1. 이스케이프 는 \t문제의 표준 이스케이프가 아니며 sed문자 클래스의 맥락에서는 백슬래시 와 문자가 각각 자신을 나타내기 [bracket-expression]때문에 표준을 명백히 위반하는 것이라고 주장할 수도 있습니다 . 여기서는 읽을 수 있는 의도를 더 명확하게 표시하기 위해 이스케이프를 사용하고 있지만 아마도 리터럴을 사용해야 할 것입니다.\t<탭>그 자리에.

  2. cut다음으로 구분됨<탭>기본값은 문자이므로 이 경우 일반 -d [delim-char]옵션은 필요하지 않습니다 . 하지만 이유를 설명하기 위해 이 메모도 추가되었습니다.

  3. 링크에서 언급했듯이 POSIX 표준에서는 [:digit:]문자 클래스에 다음이 포함되어야 합니다.0123456789모든 로케일의 문자 및 정렬 순서는 클래스의 다른 포함보다 우선합니다. C가 아닌 로케일에는 다른 지역화된 숫자 세트가 포함될 수도 있습니다. GNU는 tr여러 바이트로 표시될 수 있으므로 이를 올바르게 처리하지 못할 수 있습니다.오직그럼에도 불구하고 표준 숫자 집합은 대부분의 경우 가장 덜 놀라운 결과일 가능성이 높으므로 다음과 같은 경우 [:digit:]가 아니면 사용하세요.정말표준 아라비아 숫자 세트의 문자와 일부 문자를 일치시키려는 경우다른로케일에 따른 숫자 집합은 바람직하지 않을 수 있습니다.

관련 정보