旋转和文本处理

作者: Dave Taylor

我有一个不可告人的秘密要分享,我希望您在了解后不会因此看不起我。我曾经混迹于互联网营销界,在美国各地巡回演讲,推销我的辅导课程和 DVD 套装。是的,只需 999 美元,我就教你如何在网上赚钱,如果你是前三名注册者之一,我甚至还会免费赠送我朋友的超棒电子书!

事实是,我并没有在这个领域坚持太久,因为我更偏向于实干家而不是销售员,当人们购买我的辅导套餐时——八折优惠,但仅限现在注册!——然后却从不打开它,也不利用它至少尝试一下创建在线业务,这让我非常恼火。

幸运的是,这一切都已成为过去,但我仍然对那些商业机会推销以及他们实际销售的东西保持着兴趣。就像老套的塞信封工作(你知道的:“给我寄 200 美元到一个信封里,我就教你如何让人给你寄钱!”),事实证明,许多在线业务仍然建立在游戏搜索引擎的基础上,以获得流量到页面,销售愚蠢且通常毫无价值的东西。

而且,这些企业家玩弄 Google 和其他搜索引擎的一种方式是通过“旋转”来从一篇他们花了几美元请人写的文章中生成大量内容。

这一切都相当乏味,除了旋转的想法本身相当有趣,而且我一直想编写一个 shell 脚本,以便轻松进行文章旋转已经很长时间了。这项技术也有更多平淡无奇、不那么有争议的用途,例如在程序甚至游戏中,文本消息可以用来变化。

{想法|概念|灵感} 是,每次您使用 {单词|短语} 时,您都可以列出一组 {同义词|同义词|替代词},并且软件会自动 {随机|随意} 选择一个。

因此,前一句在旋转器中会变成“想法是,每次您使用短语时,您都可以列出一组替代词,并且软件会自动随意选择一个。” 明白了吗?很简单。

更高级的旋转器实际上可能会利用同义词库,并且每次看到一个单词时,都会自动推送一组同义词,然后另一个脚本会在每次调用时随机简化这些同义词。

事实上,去阅读垃圾博客评论或垃圾邮件,您就会看到这些无上下文句子操作的输出。它们可能……很奇怪,就像这样

她穿着连衣裙很容易到达,仍然 Beth 可能是 36 岁的男士城市仆人,在醒来时间之外的“女性”中。 她是单身,对称,此外还想实现婚姻,“最终……”

但是,嘿,仅仅因为存在不良用途,并不意味着尝试编写代码不是一个有趣的项目,对吧?我相信您在探索这个脚本时会运用自己的良好判断力,好吗?

旋转出旋转器

脚本的基本任务很简单:解析输入,隔离每个单词选择块,随机选择一个,然后重新组装所有内容并显示出来。

为了使事情变得更容易,我将首先使用 fmt 将每个段落变成一个很长的行。这样,我就可以将输入分解为没有单词选择块的行和有单词选择块的行


fmt -w$bigwidth "$1" | tr '{' '\n' | tr '}' '\n'

像 {this|demo} 这样的输入行然后会转换。


An input line like
this|demo
would then transform.

看看它是如何工作的?我将在过程结束时再次使用 fmt 来清理输出。

大多数人没有意识到的 shell 脚本编程的一个方面是,每个循环结构都充当其自己的子 shell,因此与其浪费空间和时间使用临时文件,不如将 fmt|tr 序列的输出直接管道传输到 while 循环中


fmt -w$bigwidth "$1" | tr '{' '\n' | tr '}' '\n' | \
while read line
do
  if [ $( echo "$line" | grep -c '|' ) -gt 0 ] ; then
    echo "SPIN THIS: $line"
  else
    echo "$line"
  fi
  lines=$(( $lines + 1 ))
done

看看 fmt 行是如何以 | \ 结尾的,并且直接馈送到 while 循环中?非常方便的结构!

现在我将使用示例输入文件运行此代码片段,看看会发生什么


$ sh spinner.sh spinme.txt
The
SPIN THIS: idea|concept|inspiration
is that each time you'd use a
SPIN THIS: word|phrase
you instead list a set of
SPIN THIS: similar words|synonyms|alternative words
and the software automatically picks one
SPIN THIS: randomly|at random
.

单独一行上的那个讨厌的句点是一个稍后需要修复的故障,但脚本的基本结构是合理的:您可以解析和分解输入文件数据,并识别哪些新行是选择器行。

旋转函数

与其仅仅在有选择的行之前添加 SPIN THIS:,不如将其放在一个函数调用中,调用一个单独的代码块来完成实际工作。

该函数最有趣的部分之一是它如何计算给定字符串中有多少个选项。它是“字符串 Y 中出现多少次 X?”这个一般问题的具体实例,并且它利用了 grep 的鲜为人知的 -o 标志


grep -o '|' <<< "$*" | wc -l

深吸一口气;我可以向您解释清楚! <<< 符号是您希望已经在脚本中看到的此处文档 (<<) 的变体。不同之处在于,结果作为标准输入上的单个字符串馈送。

"$*" 生成作为参数传递给脚本主块中函数的整个参数; | 是被计数的字符,当然,wc -l 生成匹配行的数量(在本例中,是行中分隔符的数量)。

所有这些,但它还不太符合我的要求,因为像 word|phrase 这样的行有一个分隔符,但有两个选择。以下是我在这个函数的第一个骨架版本中解决这个问题的方法


function spinline()
{
  source="$*"
  choices=$(grep -o '|' <<< "$*" | wc -l)
  choices=$(( $choices + 1 ))
  echo $choices options, spinning --- $source
}

使用中


$ sh spinner.sh spinme.txt
The
3 options, spinning --- idea|concept|inspiration
is that each time you'd use a
2 options, spinning --- word|phrase
you instead list a set of
3 options, spinning --- similar words|synonyms|alternative words
and the software automatically picks one
2 options, spinning --- randomly|at random
.

这个月就到这里。下个月,我将完成该函数,包括实现一种从一组 n 个选项中随机选择一个条目的方法,然后输出清理后的副本,准备在您想要的任何程序或实用程序中使用。

Dave Taylor 在 UNIX 和 Linux 系统上编写 shell 脚本已经很长时间了。他是 Learning Unix for Mac OS XWicked Cool Shell Scripts 的作者。您可以在 Twitter 上找到他 @DaveTaylor,您可以通过他的技术问答网站联系他:Ask Dave Taylor

加载 Disqus 评论