여러 줄을 한 줄로 변환하되 단락은 유지하는 방법

여러 줄을 한 줄로 변환하되 단락은 유지하는 방법

철자 오류가 있는 경우 버전 관리를 더 쉽게 하기 위해 각 문장이 별도의 줄에 있는 여러 개의 (마크다운) 텍스트가 있다고 가정해 보겠습니다. 예 file.txt:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Dictum sit amet justo donec enim diam vulputate.
Nunc faucibus a pellentesque sit amet.

Quis enim lobortis scelerisque fermentum dui faucibus in.
Leo duis ut diam quam nulla porttitor massa id neque.
Vitae tortor condimentum lacinia quis vel eros.

다음과 같이 각 단락을 한 줄로 변환하려면 어떻게 해야 합니까?

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Dictum sit amet justo donec enim diam vulputate. Nunc faucibus a pellentesque sit amet.

Quis enim lobortis scelerisque fermentum dui faucibus in. Leo duis ut diam quam nulla porttitor massa id neque. Vitae tortor condimentum lacinia quis vel eros. Velit euismod in pellentesque massa placerat duis ultricies lacus.

\n내 생각은 마침표 와 공백이 아닌 문자 .사이의 개행 문자를 찾아서 바꾸는 것입니다 \S. regex101에서 이 작업을 수행하는 방법을 알아냈습니다.여기하지만 내 bash 쉘에서 사용할 수 있는 더 짧은 tr/sed/awk가 있는지 궁금합니다. 그것은 마치cat file.txt | ???

답변1

perl단락 모드가 전달되었습니다.-00 perlruninput플래그이므로 모든 내부 개행 문자를 공백으로 바꾸면 다음과 같습니다.

$ wc -l input
       7 input
$ perl -00 -pe 's/\n(?!\Z)/ /g' input | wc -l
       3
$ 

비트 (?!\Z)는 각 단락의 끝에서 개행을 바꾸지 않아 단락 경계를 유지하는 것입니다.

또 다른 옵션은 입니다 lex. 이는 몇 가지 까다로운 문제, 특히 EOFPOSIX에서 요구하는 대로 최종 개행 문자를 처리하는 방법과 항상 포함할지 여부, 그리고 단락 정의(정확히 두 개의 개행 문자입니까, 아니면 임의의 숫자입니까?)를 드러냅니다.

%%

[\n][\n]+ { printf("%s", yytext); }
\n        { int c = input();
            /* TODO book docs say this should return EOF on EOF ?? */
            if (c == 0) {
                putchar('\n');
                yyterminate();
            } else {
                printf(" %c", c);
            }
          }
<<EOF>>   { putchar('\n'); yyterminate(); }

%%

int main(int argc, char *argv[])
{
    return yylex();
}

그 이상이 필요할 수도 있습니다

$ make paranlneg
lex  -o lex.paranlneg.c paranlneg.l
egcc -O2 -pipe    -o paranlneg lex.paranlneg.c  -ll
rm -f lex.paranlneg.c
$ perl -E 'say "a\nb\n\nc\nd"' | ./paranlneg
a b

c d
$ 

답변2

~처럼@thrig Perl 기반 답변하지만 GNU Awk를 사용하면:

$ gawk -vRS= '{$1=$1; printf $0 RT}' file.txt
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Dictum sit amet justo donec enim diam vulputate. Nunc faucibus a pellentesque sit amet.

Quis enim lobortis scelerisque fermentum dui faucibus in. Leo duis ut diam quam nulla porttitor massa id neque. Vitae tortor condimentum lacinia quis vel eros.

fmt빠른 해결을 위해 적절하게 큰 너비 값으로 Coreutils 유틸리티를 사용할 수 있습니다 .

fmt -w1000 file.txt

(기본적으로 각 마침표 뒤에 이중 공백이 추가되지만).

답변3

GNU 기반 sed접근 방식:

tr문자를 문자로 대체한 다음 를 사용하여 두 개 이상의 연속 문자 시퀀스를 이중 문자로 변경하고 나머지 문자를 공백으로 바꾸는 데 사용할 수 있습니다 .<newline><NUL>sed<NUL><newline>tr<NUL>

$ tr '\n' '\0' <file.txt | sed 's/\o000\{2,\}/\n\n/g' | tr '\0' ' ' | sed --null-data 's/ $/\n/'

여기서 마지막 줄은 sed마지막 남은 공간을 새 줄로 바꾸면 됩니다.

또는 (더 간결하게) sed파일을 일련의 null로 끝나는 줄로 처리하고(즉, sed단일 줄로 처리하도록 지시하고 공백이 아닌 단일 줄 바꿈의 모든 앞뒤 항목을 바꾸도록 지시할 수 있습니다. 단일 공백이 있는 문자:

$ sed --null-data 's/\([^[:space:]]\)\n\([^[:space:]]\)/\1 \2/g' file.txt

이렇게 하면 단락 사이의 세로 간격, 즉 연속된 새 줄의 수도 유지됩니다. 나는 문장이 마침표로 끝나지 않는 경우를 처리하기 위해 공백이 아닌 문자(점 대신)와 개행 문자를 검색하는 것을 선호합니다.

관련 정보