• 力扣shell刷题


    192. 统计词频

    写一个 bash 脚本以统计一个文本文件 words.txt 中每个单词出现的频率。

    为了简单起见,你可以假设:

    words.txt只包括小写字母和 ' ' 。
    每个单词只由小写字母组成。
    单词间由一个或多个空格字符分隔。
    
    • 1
    • 2
    • 3

    示例:

    假设 words.txt 内容如下:

    the day is sunny the the
    the sunny is is
    
    • 1
    • 2

    你的脚本应当输出(以词频降序排列):

    the 4
    is 3
    sunny 2
    day 1
    
    • 1
    • 2
    • 3
    • 4

    说明:

    • 不要担心词频相同的单词的排序问题,每个单词出现的频率都是唯一的。
    • 你可以使用一行 Unix pipes 实现吗?

    题解一

    cat words.txt | tr -s ' ' '\n' | sort | uniq -c | sort -r | awk '{ print $2, $1 }'
    
    • 1

    说明

    tr 命令用于转换或删除文件中的字符
    -s:缩减连续重复的字符成指定的单个字符
    sort:排序
    uniq 命令用于检查及删除文本文件中重复出现的行列,一般与 sort 命令结合使用。
    -c:在每列旁边显示该行重复出现的次数。
    -r:以相反的顺序来排序  就是反一下一行的数据
    awk '{print $2, $1}' 打印把第一列和第二列数字反一下
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    题解二

    cat words.txt | xargs -n 1 | sort | uniq -c | sort -nr | awk '{print $2" "$1}'
    
    • 1

    说明

    xargs -n1  使用 xargs 将所有行转为单列显示
    sort -nr 表示依照数值的大小降序排序
    uniq -c 表示在每列旁边显示该行重复出现的次数
    awk + print 函数将 1、2 列位置互换
    
    • 1
    • 2
    • 3
    • 4

    题解三

    cat words.txt | 
    awk '{ 
        for(i=1;i<=NF;i++){
            count[$i]++
        } 
    } END { 
        for(k in count){
            print k" "count[k]
        } 
    }' | 
    sort -rnk 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    说明

    在awk中我们用一个字典(?)count储存每个单词的词频,先遍历每一行(awk自身机制)的每一个字段(i<=NF),然后用该字段本身作为key,将其value++;最后用一个for循环输出count数组中的每个元素的key(词)及其value(词频)。
    
    最后用|管道命令传给sort命令:
    
        -r是倒序排序,相当于DESC
        -n是将字符串当作numeric数值排序
        -k则指定用于排序的字段位置,后跟2指将第二位的count[k](词频)作为排序的key
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    题解四 python版本(运行比较慢)

    python3 -c "a=open('words.txt').read().split();from collections import Counter;c=list(Counter(a).items());c.sort(key=lambda x:-x[1]);[print(x,y)for x,y in c]"
    
    • 1

    题解五

    # 统计词频率
    declare -A F # 键值对数组 记录词与出现频率
    for word in `< words.txt`;do  # 使用重定向符 <, 而不是 cat 命令
        ((F[$word]++)) # C风格的增1,这里数组变量名前不能加 $,否则有语法错误
    done
    # 按频率高低打印
    while [[ ${#F[@]} -gt 0 ]];do  # 数组元素个数
        mx=0  # 出现次数最多词 数
        unset wd # 对应上面的 词
        for i in ${!F[*]};do  # 遍历 数组的 key
            [[ ${F[$i]} -gt $mx ]]  && {  # 比较最大次数词
                mx=${F[$i]}
                wd="$i"; }
        done
        [[ $mx -ne 0 ]] && echo $wd $mx # 打印
        unset F[$wd] # 删除 已经打印了的词
    done
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    题解六

    cat words.txt | xargs -n 1 | awk '{
        if($1 in data)
            data[$1] = data[$1] + 1
        else
            data[$1] = 1
     } END {for(str in data) print data[str],str}' | sort -rn | awk '{print $2, $1}'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    第一步:将文件单词进行每行一个输出(使用xargs命令)(此处可以不用,也可以使用awk脚本NF处理)
    第二步:使用awk数组进行统计(数组+MAP概念),并输出
    第三步:将输出元素进行倒序排序 + 输出位置调整 (sort+awk

    193. 有效电话号码

    给定一个包含电话号码列表(一行一个电话号码)的文本文件 file.txt,写一个单行 bash 脚本输出所有有效的电话号码。

    你可以假设一个有效的电话号码必须满足以下两种格式: (xxx) xxx-xxxx 或 xxx-xxx-xxxx。(x 表示一个数字)

    你也可以假设每行前后没有多余的空格字符。

    示例:

    假设 file.txt 内容如下:

    987-123-4567
    123 456 7890
    (123) 456-7890
    
    • 1
    • 2
    • 3

    你的脚本应当输出下列有效的电话号码:

    987-123-4567
    (123) 456-7890
    
    • 1
    • 2

    题解一

    grep -P '^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$' file.txt
    
    • 1

    题解二

    grep -P '^((\(\d{3}\) )|(\d{3}-))\d{3}-\d{4}$' file.txt
    
    • 1

    说明

    -P 使用 Perl 拓展正则,主要是为了支持\d匹配数字
    ^ 要求匹配的字符串是在行首,防止出现abc123-456-7890这种情况
    $ 要求匹配的字符串在行尾,防止出现123-456-7890abc这种情况
    \d 匹配数字0-9 等价于[0-9]
    {3} 前面的匹配出现三次,就是匹配连续三个数字
    () 以及中间的| 用来分组,括号内的是一组,这里嵌套了一次括号并用了|(),为了实现的是(\(\d{3}\) )(\d{3}-)的二选一
    \(\) 括号转义
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    题解三 (速度最快!)

    sed -rn "/^((\([0-9]{3}\) )|[0-9]{3}-)[0-9]{3}-[0-9]{4}$/p" file.txt
    
    • 1

    说明

    sed -rn 使用Regex+不输出加工过程
    
    ^((\([0-9]{3}\) )|[0-9]{3}-) #(开头+3数字+)结尾+空格 或者 3数字+一个连接符 
    
    [0-9]{3}-[0-9]{4}$ # 3数字+连接符+4数字+本行结束符
    
    /p 打印匹配
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    题解四

    cat file.txt | grep -P "^(\([0-9]{3}\)\s|[0-9]{3}-)[0-9]{3}-[0-9]{4}$"
    
    • 1

    题解五 python 运行最慢

    python3 -c "import re;lines=open('file.txt').readlines();lines=[i.strip()for i in lines];ans=[i for i in lines if re.match('^\(\d{3}\) \d{3}-\d{4}$',i) or re.match('^\d{3}-\d{3}-\d{4}$',i)];   print('\n'.join(ans))"
    
    • 1

    194. 转置文件

    给定一个文件 file.txt,转置它的内容。

    你可以假设每行列数相同,并且每个字段由 ’ ’ 分隔。

    示例:

    假设 file.txt 文件内容如下:

    name age
    alice 21
    ryan 30
    
    • 1
    • 2
    • 3

    应当输出:

    name alice ryan
    age 21 30
    
    • 1
    • 2

    题解一

    # 获取第一行,然后用wc来获取列数
    COLS=`head -1 file.txt | wc -w`
    # 使用awk依次去输出文件的每一列的参数,然后用xargs做转置
    for (( i = 1; i <= $COLS; i++ )); do
        # 这里col就是在代码里要替换的参数,而它等于$i
        awk -v col=$i '{print $col}' file.txt | xargs
    done
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    题解二

    columns=$(cat file.txt | head -n 1 | wc -w)
    for i in $(seq 1 $columns)
    do
    awk '{print $'''$i'''}' file.txt | xargs
    done
    
    • 1
    • 2
    • 3
    • 4
    • 5

    题解三

    awk '{
        for (i=1;i<=NF;i++){
            if (NR==1){
                res[i]=$i
            }
            else{
                res[i]=res[i]" "$i
            }
        }
    }END{
        for(j=1;j<=NF;j++){
            print res[j]
        }
    }' file.txt
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    题解四

    COUNT=`head -1 file.txt | wc -w`
    for (( i = 1; i <= $COUNT; i++ )); do
    cut -d' ' -f$i file.txt | xargs
    done
    
    • 1
    • 2
    • 3
    • 4

    题解五

    COUNT=`head -1 file.txt | wc -w`
    for (( i = 1; i <= $COUNT; i++ )); do
    awk -v arg=$i '{print $arg}' file.txt | xargs
    done
    
    • 1
    • 2
    • 3
    • 4

    题解六

    #!/bin/bash
    line=`cat file.txt|awk '{print NF}'|head -n 1`
    for n in $(seq 1 ${line});
    do
    
       cat  file.txt |awk -v n=$n '{print $n}' |xargs echo 
    
    done
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    195. 第十行

    给定一个文本文件 file.txt,请只打印这个文件中的第十行。

    示例:

    假设 file.txt 有如下内容:

    Line 1
    Line 2
    Line 3
    Line 4
    Line 5
    Line 6
    Line 7
    Line 8
    Line 9
    Line 10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    你的脚本应当显示第十行:

    Line 10
    
    • 1

    说明:
    \1. 如果文件少于十行,你应当输出什么?
    \2. 至少有三种不同的解法,请尝试尽可能多的方法来解题。

    题解一

    sed -n "10p" file.txt
    
    • 1

    题解二

    tail -n +10 file.txt | head -1
    
    • 1

    对于行数的提取

    awk '{print NR}' file.txt | tail -n1
    10
    awk 'END{print NR}' file.txt 
    10
    grep -nc "" file.txt 
    10
    grep -c "" file.txt 
    10
    grep -vc "^$" file.txt 
    10
    grep -n "" file.txt|awk -F: '{print '}|tail -n1 | cut -d: -f1
    10
    grep -nc "" file.txt
    10
    sed -n "$=" file.txt 
    10
    wc -l file.txt 
    10 file.txt
    cat file.txt | wc -l
    10
    wc -l file.txt | cut -d' ' -f1
    10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    回忆三年浮沉
    C++11 条件变量
    LeetCode - 79 单词搜索
    django rest framework 学习笔记-实战商城3
    人工智能-线性回归1--损失函数、正规方程、梯度下降法
    《牛客题霸-算法篇》刷题之NC57 反转数字
    解决pycharm中PIL安装失败
    Netty 4.1.98.Final 发布
    钡铼profinet总线模块可以拓展IO
    python中sklearn库在数据预处理中的详细用法,及5个常用的Scikit-learn(通常简称为 sklearn)程序代码示例
  • 原文地址:https://blog.csdn.net/weixin_45682261/article/details/126070556