在每个第 2000 个字符之前的最后一个空格处将大型纯文本文件拆分为较小的文件

在每个第 2000 个字符之前的最后一个空格处将大型纯文本文件拆分为较小的文件

要求:BSD 版本的工具而不是 GNU。

我有一个 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

Shell 语言非常擅长将事物分割成单词,只要您不需要保留输入中的精确空格(例如,连续的空格可以合并为单个空格)。

通过向前看,处理可以变得更容易一些 - 对于每个单词,如果它适合一个文件,则添加它。否则继续处理下一个文件。换行类似:

#!/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在创建单词数组之前设置(内部字段分隔符)来更改。

相关内容