큰 파일에서 줄 바꿈이 포함 된 문자열 바꾸기


16

누구나 메모리를 효율적으로 사용하여 문자열을 "이진"검색 / 바꾸기위한 비 라인 기반 도구를 알고 있습니까? 이 질문 도 참조하십시오 .

이 작업과 비슷한 + 2GB 텍스트 파일을 처리하려고합니다.

sed -e 's/>\n/>/g'

즉, 나는 이후에 발생하는 모든 줄 바꿈을 제거하고 싶지만 >다른 곳에서는 제거하지 않기를 원합니다 tr -d.

이 명령 ( 유사한 질문에 대한 답변 에서 얻은 )은 다음과 couldn't re-allocate memory같이 실패합니다 .

sed --unbuffered ':a;N;$!ba;s/>\n/>/g'

C에 의지하지 않고 다른 방법이 있습니까? 나는 펄을 싫어하지만,이 경우 예외를 기꺼이 :-)

나는 데이터에서 발생하지 않는 문자를 확신하지 못하므로 \n다른 문자로 임시 대체 하는 것이 가능하면 피하고 싶은 것입니다.

좋은 아이디어가 있습니까?


옵션을 사용해 보셨습니까 --unbuffered?
ctrl-alt-delor 12

유무에 관계없이 --unbuffered메모리가 부족
MattBianco

무엇을 $!합니까?
ctrl-alt-delor

첫 번째 sed 명령의 문제점입니다. 두 번째는 모든 것을 패턴 공간으로 읽는 것처럼 보이지만 $!그래도 모르겠습니다 . 이것은 많은 메모리 가 필요할 것으로 예상됩니다 .
ctrl-alt-delor

문제는 sed가 모든 것을 행으로 읽는 것이므로 첫 번째 명령은 줄 바꿈을 제거하지 않습니다. 텍스트를 한 행씩 다시 출력하기 때문입니다. 두 번째 명령은 해결 방법입니다. sed이 경우 적절한 도구가 아니라고 생각 합니다.
MattBianco

답변:


14

이것은 정말로 Perl에서 사소한 것이므로 싫어해서는 안됩니다!

perl -i.bak -pe 's/>\n/>/' file

설명

  • -i: 파일을 제자리에 편집하고라는 원본의 백업을 만듭니다 file.bak. 백업을 원하지 않으면 perl -i -pe대신 사용하십시오.
  • -pe: 입력 파일을 한 줄씩 읽고으로 주어진 스크립트를 적용한 후 각 줄을 인쇄하십시오 -e.
  • s/>\n/>/: 같은 치환 sed.

그리고 여기 awk접근 방식이 있습니다 :

awk  '{if(/>$/){printf "%s",$0}else{print}}' file2 

3
+1. awk golf :awk '{ORS=/>$/?"":"\n"}1'
glenn jackman

1
내가 일반적으로 펄을 싫어하는 이유는 내가이 답변을 선택했던 것과 같은 이유이다. 간단한 "sed 패턴"과 함께 perl -pe를 사용하는 것은 복잡한 sed- 표현식보다 읽기 쉽습니다.
MattBianco

3
@MattBianco는 충분히 공정하지만 펄과는 아무런 관련이 없습니다. Gnouc이 사용한 모습은 Perl의 잘못이 아닌 일부 정규 표현식 언어 (PCRE 포함)의 기능입니다. 또한 ':a;N;$!ba;s/>\n/>/g'귀하의 질문 에이 sed monstrosity 를 선보인 후에 는 가독성에 대해 불평 할 권리를 포기했습니다! : P
terdon

트윗 담아 가기 나는 foo ? bar : baz구조물 을 가지고 놀고 있었지만 작동시키지 못했습니다.
terdon

@ terdon : 그래, 내 실수. 삭제하십시오.
cuonglm

7

perl솔루션 :

$ perl -pe 's/(?<=>)\n//'

설명

  • s/// 문자열 대체에 사용됩니다.
  • (?<=>) lookbehind 패턴입니다.
  • \n 개행과 일치합니다.

전체 패턴은 그 >전에있는 모든 개행을 제거하는 것을 의미 합니다.


2
프로그램의 일부가 무엇인지 언급하고 싶습니까? 나는 항상 배우고 싶습니다.
MattBianco

2
왜 뒤돌아보기를 귀찮게합니까? 왜 안돼 s/>\n/>/?
terdon

1
또는 s/>\K\n//작동 할 것입니다
glenn jackman 2016 년

@terdon : 그래도 내가 제일 먼저 교체 대신 제거
cuonglm

@glennjackman : 좋은 지적입니다!
cuonglm

3

이건 어때:

sed ':loop
  />$/ { N
    s/\n//
    b loop
  }' file

GNU sed의 경우 질문에 따라 -u( --unbuffered) 옵션을 추가 할 수도 있습니다 . GNU sed는 간단한 단일 라이너로 이것을 기쁘게 생각합니다.

sed ':loop />$/ { N; s/\n//; b loop }' file

\n파일이로 끝나더라도 마지막을 제거하지는 않지만 >\n어쨌든 바람직합니다.
Stéphane Chazelas

@ StéphaneChazelas, 왜 종결 }은 별도의 표현이 필요합니까? 이것은 여러 줄 표현으로 작동하지 않습니까?
Graeme

1
그와 POSIX의 SED는에서 작동 b loop\n}또는 -e 'b loop' -e '}'하지만,하지 b loop;}하지 확실히하고 b loop}있기 때문에 };레이블 이름에 유효 (그들의 권리 염두에두고 아무도 그것을 사용하지 않을 것이다하지만. 그리고 GNU가 나오지도 그 수단은 POSIX 준수하지)과 }분리 명령 요구 로부터 b명령.
Stéphane Chazelas

@ StéphaneChazelas, GNU sed는 위의 모든 것에 만족합니다 --posix! 이 표준에는 중괄호 표현식에 대한 다음 내용도 있습니다 The list of sed functions shall be surrounded by braces and separated by <newline>s. 이것은 세미콜론이 중괄호 밖에 사용해야한다는 것을 의미하지 않습니까?
Graeme

@mikeserv,로 끝나는 연속 줄을 처리하려면 루프가 필요합니다 >. 원본은 하나도 없었습니다 .Stéphane이 지적했습니다.
Graeme

1

sedN명령 과 함께 사용할 수는 있지만 다른 방법을 추가 할 때마다 패턴 공간에서 한 줄을 삭제하는 것이 요령입니다 (따라서 패턴 공간에는 전체를 읽지 않고 항상 두 개의 연속 된 줄만 포함됩니다) 파일)-시도

sed ':a;$!N;s/>\n/>/;P;D;ba'

편집 : Peteris Krumins의 유명한 Sed One-Liners를 다시 읽은 후 더 나은 sed해결책이 있다고 생각 합니다.

sed -e :a -e '/>$/N; s/\n//; ta'

이것은 이미 >끝에 일치 하는 경우에만 다음 줄을 추가하고 연속 일치하는 줄의 경우를 처리하기 위해 조건부로 루프 해야 합니다 (Krumin의 39입니다. 백 슬래시로 끝나는 경우 다음 줄을 추가하십시오 "\">for \를 결합 문자로 대체 하고 결합 문자가 출력에 유지된다는 사실을 제외하고는 정확히 제외됩니다 .


2
2 개의 연속 된 줄로 끝나는 경우 작동하지 않습니다 >(GNU에만 해당)
Stéphane Chazelas

1

sed최종 개행없이 출력을 방출하는 방법을 제공하지 않습니다. N기본적으로 사용하는 접근 방식 은 작동하지만 불완전한 줄을 메모리에 저장하므로 줄이 너무 길면 실패합니다 (sed implentations는 일반적으로 매우 긴 줄을 처리하도록 설계되지 않았습니다).

대신 awk를 사용할 수 있습니다.

awk '{if (/<$/) printf "%s", $0; else print}'

다른 방법은 tr개행 문자를 "지루한"자주 발생하는 문자로 바꾸는 데 사용 하는 것입니다. 공간이 여기에서 작동 할 수 있습니다. 데이터의 모든 라인 또는 최소한 많은 라인에 나타나는 경향이있는 문자를 선택하십시오.

tr ' \n' '\n ' | sed 's/> />/g' | tr '\n ' ' \n'

두 가지 방법 모두 이미 다른 답변에 더 효과적으로 적용되도록 여기에 설명되어 있습니다. 그리고 그의 접근 방식 sed은 2.5 기가 바이트 버퍼가 없으면 작동하지 않습니다.
mikeserv

누구든지 awk에 대해 언급 했습니까? 오, 나는 그것을 놓쳤다. 어떤 이유로 든 terdon의 대답에서 펄 만 발견했다. 아무도 tr접근 방식에 대해 언급하지 않았습니다. mikeserv 당신도 ​​사용하는 다른 (유효하지만 덜 일반적인) 접근 방식을 게시했습니다 tr.
Gilles 'SO- 악마 그만해'

유효하지만 덜 일반적인 소리는 방금 작동하는 대상 솔루션 이라고 불렀습니다 . 나는 0 upvotes를 가지고 있기 때문에 이상한 것이 유용 하지 않다고 주장하기가 어렵다고 생각합니다 . 내 솔루션과 보다 일반적인 제품 사이에서 볼 수있는 가장 큰 차이점 은 일반적으로 문제를 해결할 있지만 내 문제를 구체적으로 해결 한다는 것 입니다. 그럴 경우 가치가있을 수 있습니다. 그리고 심지어 투표를 취소 할 수도 있습니다. 그러나 그들 사이에 7 시간의 성가신 문제와 다른 사람들을 모방 한 당신의 답 이 되풀이되는 주제도 있습니다. 이것을 설명 할 수 있습니까?
mikeserv



-1

이 작업을 수행하는 방법에는 여러 가지가 있으며 대부분 여기에 정말 좋지만이 방법이 내가 가장 좋아하는 것 같습니다.

tr '>\n' '\n>' | sed 's/^>*//;H;/./!d;x;y/\n>/>\n/'

또는:

tr '>\n' '\n>' | sed 's/^>*//' | tr '\n>' '>\n'

첫 번째 답변을 전혀 얻지 못했습니다. 두 번째 요소의 우아함에 감탄하지만을 제거해야한다고 생각합니다 *. 현재 상태에서는로 끝나는 행 뒤에 빈 줄이 모두 삭제됩니다 >. … 흠. 질문을 되돌아 보면 조금 모호하다는 것을 알았습니다. 문제는 말한다, "나는 이후에 발생하는 모든 줄 바꿈을 제거하려면 >..."나는 그는 의미로 해석 >\n\n\n\n\nfoo변경해야합니다 \n\n\n\nfoo,하지만 난 가정 foo원하는 출력 될 수 있습니다.
Scott

@Scott - 난 다음에 변화 테스트 : printf '>\n>\n\n>>\n>\n>>>\n>\nf\n\nff\n>\n' | tr '>\n' '\n>' | sed 's/^>*//;H;/./!d;x;y/\n>/>\n/'- 그 결과 >>>>>>>>>>f\n\nff\n\n첫 번째 대답과 나를 위해. 나는 그것을 고치고 싶기 때문에 당신이 그것을 깨기 위해 무엇을하고 있는지 궁금합니다. 두 번째 요점과 관련하여 나는 그것이 모호하다는 것에 동의하지 않습니다. 영업 이익은 제거 요청하지 않고 모든 > 이전\n ewline을 대신 제거하기 위해 모든 \n ewlines 다음>.
mikeserv 2016 년

1
예, 그러나 유효한 해석은 >\n\n\n\n\n첫 번째 줄 바꿈 만 >; 다른 모든 사람들은 다른 개행을 따르고 있습니다. OP의“이것이 효과가 있다면 내가 원하는 것”이라는 제안은 sed -e 's/>\n/>/g'아니었다 sed -e 's/>\n*/>/g'.
Scott

1
@ 스콧-제안이 작동하지 않았고 결코 할 수 없었습니다. 코드를 완전히 이해하지 못하는 사람의 코드 제안이 사람이 사용하는 평범한 언어와 같은 유효한 해석 포인트로 간주 될 수 있다고 생각하지 않습니다. 게다가, 출력 - 실제로 일 경우는 -의 s/>\n/>/>\n\n\n\n\n여전히 뭔가 될 것 s/>\n/>/겠습니까 편집.
mikeserv 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.