【问题标题】:Match multiple characters one or more times匹配多个字符一次或多次
【发布时间】:2017-12-07 15:22:25
【问题描述】:

考虑以下问题: 我们有一串从 /dev/urandom 流出的随机字符,我们希望以这样的方式处理它,以得到满足某些条件的恒定长度的字符串。 例如,如果我们运行以下命令 5 次,我们会得到:

cat /dev/urandom |tr -dc A-Z5|head -c${1:-30}
DLZEZDATSTDN55BNVDSNRFSLRKHDGR
AVCRIE5OAFBUWZZYQYQWCTAZSNMQAA
HSTFN5AQNWILXMSZCBIGREPNCFGPDM
AZJNEUQRCDYSKXMQDUHVTOFEOAYPHF
ANFDWHHZHLAGXCPKWLQESSZLEZYNDC

现在,这些字符串满足我需要的条件,但只是部分满足。 例如。我需要数字 5 在一个字符串中出现至少 2 次但不超过 7 次,并且任何字母都不应出现超过 10 次。 我应该如何自定义上面的命令来得到这个结果?

【问题讨论】:

  • 使用正则表达式将其连接到某个地方,使用正则表达式检查您的条件。
  • 如果某些字符串不满足条件,是否应该输出任何调试信息?

标签: regex string bash


【解决方案1】:

使用带有 OP 所需过滤器的函数的 Bash 解决方案。

解释:

filter 是字符出现 5 次的计数。我通过使用 tr 删除字符串上除字符 5 之外的所有内容,然后计算剩余的字符数来得到这一点。

grep -E '(.)(.\1){10}'* 是一个标准正则表达式,用于确保没有字符出现超过 10 次。

然后循环只会获取一个接一个的随机单词,直到满足所有三个条件。当然,这可能需要随机时间。 :P

function GETRANDOMWORD {
    local filter=0;
    until [[ $filter -gt 1 && $filter -lt 8 && ! $( echo "$word" | grep -E '(.)(.*\1){10}') ]]
    do
        word="$( cat /dev/urandom |tr -dc A-Z5|head -c${1:-30} )"
        filter=$( echo "$word" | tr -cd '5' | wc -c )
    done
    [[ "$word" ]] && echo "$word"
}

用法:

【讨论】:

  • 你能补充解释吗?
  • @M.Becerra 完成!
  • @MatiasBarrios 非常感谢,你太棒了。效果很好。这个社区太棒了!
【解决方案2】:

使用 GNU awk 处理:

awk -v FS="" '{ 
                  err=0; 
                  for(i=1; i<=NF; i++) { 
                      a[$i]++; 
                      if ($i~/[A-Z]/ && a[$i]>10) { err=1; break } 
                  } 
                  if (!err && (2>a[5] || a[5]>7)) err=1 
              }
              END{ if (!err) print }' <(cat /dev/urandom | tr -dc A-Z5 | head -c30)

  • FS="" - 在这种情况下,记录中的每个单独字符都成为一个单独的字段

只有在所有条件都满足的情况下,上面才会打印一个随机字符串。

【讨论】:

  • 谢谢!你的解决方案也很好,我真的很感激。我会保留他们两个。我只选择第一个答案,因为我理解得更好。我在 Bash 脚本方面没有太多经验,更不用说 awk。
最近更新 更多