요구사항: GNU 대신 BSD 버전의 도구.
웹사이트에서 주간 뉴스레터를 스크랩하고, 주요 섹션을 가져와서 일반 텍스트로 변환하고, 파일에 저장하는 ZSH 스크립트가 있습니다. 그런 다음 뉴스레터의 여러 부분을 별도의 파일(file1.txt...)로 나누고 각 파일을 해당 대시보드에 업로드합니다. 이를 통해 특정 섹션의 정보를 역사적으로(수동/시각적으로) 정렬할 수 있습니다. 이러한 섹션에는 정보 출처에 대한 하이퍼링크도 포함되어 있는 경우가 많습니다. 대시보드 게시물의 길이는 2000자(바이트)로 제한됩니다. 원래는 split -b 2000 file1.txt a
(file2.txt는 b, file3.txt는 c)를 사용했는데, 여기서 문제는 2000번째 문자가 공백인 경우가 거의 없어서 단어와 URL이 다른 게시물로 잘리는 경우가 많다는 것입니다.
그렇다면 각 2000번째 문자 사이의 마지막 공백에서 이 파일을 분할하려면 어떻게 해야 합니까?
이는 다음과 같이 불완전할 수도 있습니다.
count 2000 characters
backup to last withespace
put everything that came before into a file
count from that whitespace 2000 more characters
backup to previous whitespace
put everything that came between last split point and this whitespace into next file
loop.
파일 끝에 도달할 때까지 반복합니다.
답변1
다음과 같이 보일 수 있습니다:
process() {
do-what-you-have-to-do-with-the-chunk $1
}
chunk_size=2000
file=file1.txt
set -o extendedglob # needed for (#cmin,max), ## and (#b)
# contents of the file trimmed of leading and trailing whitespace
text=${${$(<$file)%%[[:space:]]##}##[[:space:]]##}
while (( $#text > chunk_size )); do
if [[ $text = (#b)(?(#c0,$((chunk_size - 1)))[^[:space:]])[[:space:]]##(*) ]]; then
process $match[1]
text=$match[2]
else
print -ru2 Text cannot be split
exit 1
fi
done
if [[ -n $text ]]; then
# last chunk
process $text
done
길이는 수량에 따라 계산됩니다.특징, 아니요바이트. 바이트 단위로 계산할 수 있지만 set +o multibyte
이는 다중 바이트 공백 문자가 무시된다는 의미이기도 합니다. 내 영국 로케일에서는 대부분의 공백 문자가 여러 바이트로 인코딩되지만 가장 일반적으로 사용되지는 않습니다. 그들은:
09 U+0009 CHARACTER TABULATION
0A U+000A LINE FEED
0B U+000B LINE TABULATION
0C U+000C FORM FEED
0D U+000D CARRIAGE RETURN
20 U+0020 SPACE
E1 9A 80 U+1680 OGHAM SPACE MARK
E2 80 80 U+2000 EN QUAD
E2 80 81 U+2001 EM QUAD
E2 80 82 U+2002 EN SPACE
E2 80 83 U+2003 EM SPACE
E2 80 84 U+2004 THREE-PER-EM SPACE
E2 80 85 U+2005 FOUR-PER-EM SPACE
E2 80 86 U+2006 SIX-PER-EM SPACE
E2 80 88 U+2008 PUNCTUATION SPACE
E2 80 89 U+2009 THIN SPACE
E2 80 8A U+200A HAIR SPACE
E2 80 A8 U+2028 LINE SEPARATOR
E2 80 A9 U+2029 PARAGRAPH SEPARATOR
E2 81 9F U+205F MEDIUM MATHEMATICAL SPACE
E3 80 80 U+3000 IDEOGRAPHIC SPACE
답변2
쉘 언어는 입력에서 정확한 공백을 유지할 필요가 없는 한 항목을 단어로 분할하는 데 매우 능숙합니다(예를 들어 연속 공백을 단일 공백으로 병합할 수 있음).
앞을 내다보면 처리가 조금 더 쉬워질 수 있습니다. 각 단어에 대해 파일에 맞으면 추가하세요. 그렇지 않으면 다음 파일 처리를 계속합니다. 줄 바꿈은 다음과 유사합니다.
#!/usr/bin/env zsh
inFile=$1
fileAsWords=($(<$inFile))
outfileNum=0
outputText=
sep=
lineLen=0
eol=$'\n'
for word in $fileAsWords; do
if (( ${#outputText} + ${#sep} + ${#word} + ${#eol} > 2000 )); then
printf -v outfileName out-%04d.txt outfileNum++
print -r -- $outputText > $outfileName
outputText=
sep=
lineLen=0
fi
if (( lineLen > 0 && lineLen + ${#sep} + ${#word} > 80 )); then
sep=${eol}
lineLen=0
fi
outputText+=${sep}${word}
(( lineLen += ${#sep} + ${#word} ))
sep=' '
done
if (( ${#outputText} > 0 )); then
printf -v outfileName out-%04d.txt outfileNum
print -r -- $outputText > $outfileName
fi
URL과 같은 일부 항목에 공백이 포함될 수 있는 경우 파일 간에 분할될 수 있습니다. 분할에 사용되는 문자 집합은 IFS
단어 배열을 생성하기 전에 설정(내부 필드 구분 기호)을 통해 변경할 수 있습니다.