【问题标题】:How To Delete All Words After X Characters如何删除 X 个字符后的所有单词
【发布时间】:2017-10-14 16:13:31
【问题描述】:

我阅读了这篇文章:sed delete remaining characters in line except first 5,它帮助我删除了 x 之后的所有字符。但是,我很难找到如何删除 x 个字符后的所有单词。

我从这段代码开始:

echo "StackOverflow Users Are Brilliant And Hard Working" | sed 's/.//30g'
#character 30 ---------------------^

我的尝试:

echo "StackOverflow Users Are Brilliant And Hard Working" | sed 's/ .* //30g'
#character 30 ---------------------^

在这些输出中,我要么截断最后一个单词,要么数单词。相反,我需要删除 30 个字符后的单词。我在不同的行/字长上运行它,这就是为什么我不能把它设置到单词的末尾。

期望的输出:

StackOverflow Users Are Brilliant

如果您知道如何计算 x 个字符后的单词,我们将不胜感激。

请注意:如前所述,请勿将代码更改为 33 或 34 个字符。问题的重点是删除 30 个字符后的所有 WORDS。

【问题讨论】:

    标签: linux bash unix awk sed


    【解决方案1】:

    这个awk会做

    $ awk 'BEGIN{FS=OFS="" }  length>30{i=30; while($i~/\w/) i++; NF=i-1; }1' file
    StackOverflow Users Are Brilliant
    This line has 22 chars
    

    设置FS=OFS="",使每个字符都被视为一个字段

    如果length>30 那么i=30; while($i~/\w/) i++; 即不断增加i 直到我们到达一个非alnum 字符;一旦循环结束,设置所需的NF

    length<=30 的行将按原样打印。

    使用 grep

    $ grep -oE "^.{1,29}\w*" file
    StackOverflow Users Are Brilliant
    This line has 22 chars
    

    ^.{1,29}\w* : 129 因为如果 30th char 是非 alnum 则不应该考虑它。

    【讨论】:

    • Grep 解决方案是最短的解决方案,我也试图用 grep 解决这个问题,但忘记了 ^ 并且它产生了多行。
    • @PawełTatarczuk @batMan,我实际上在我的程序中使用了 Pawel 的解决方案。但是,我之所以选择这个,是因为awkgrep 的双重答案。此外,它的得分最高,我确实欠你一个蝙蝠侠。帕维尔,我希望很多人支持你的回答,因为你给出了非常有帮助的解释。它对我帮助很大,也会帮助其他人。再次感谢蝙蝠侠 :-)
    • @DomainsFeatured:Pawel 解决方案中的问题是:如果第 30 个字符是空格,它仍然会从第 31 个开始打印下一个单词。
    • 您应该提到 awk 解决方案是 gawk 特定的,因为 1) 依赖 FS="" 将记录拆分为字符,2) 将 \w 用于单词组成字符(您应该使用\S 代替 btw),以及 3) 依靠递减 NF 从行尾删除字段。
    【解决方案2】:

    使用神奇的 substr 实用程序来简单而清醒的 awk 怎么样:

    echo "StackOverflow Users Are Brilliant And Hard Working" | awk '{print substr($0,1,34)}'
    

    如果您想将长度传递给 awk,那么下面的内容可能会对您有所帮助。

    echo "StackOverflow Users Are Brilliant And Hard Working" | awk -v end=34 '{print substr($0,1,end)}'
    

    如果您想将长度保存在 shell 变量中并希望将其传递给 awk,那么下面的内容可能对您有所帮助。

    val="34"
    echo "StackOverflow Users Are Brilliant And Hard Working" | awk -v var="$val" '{print substr($0,1,var)}'
    

    编辑: 也添加一个 sed 解决方案。

    echo "StackOverflow Users Are Brilliant And Hard Working" | sed 's/\(.\{34\}\)\(.*\)/\1/'
    

    【讨论】:

    • @DomainsFeatured,欢迎您。请参阅我的编辑添加了另外 3 种方法(包括 sed)来解决此问题,如果有任何疑问,请告诉我。
    • 哦,废话,我才意识到这行不通!我需要它处理 30 个字符,而不是 34 个 :-( 输出为:StackOverflow Users Are Brilli
    • @DomainsFeatured,我给出了 34 个字符的解决方案,因为我已经看到了您的预期输出(直到 Brilliant word),显然您可以根据需要调整字符。
    • @Down voter:请告诉我投反对票的原因?
    • 在我提出的问题中:在这些输出中,我要么截断最后一个单词,要么数单词。相反,我需要删除 30 个字符后的单词。我在不同的行/字长上运行它,所以这就是为什么我不能将它设置到单词的末尾。
    【解决方案3】:

    这可能对你有用(GNU sed):

    sed -r 's/^(.{30}\S*).*/\1/' file
    

    这会保留前 30 个字符和任何后续的非空格字符。

    注意如果第 30 个字符是空格,则将包含以下单词,因此正则表达式可能是:

    sed -r 's/^(.{29}\S*).*/\1/' file
    

    【讨论】:

    • 嘿@potong,感谢您的精彩回答和解释。这很有意义:-)
    【解决方案4】:

    你可以用 sed 做到这一点:

    echo "StackOverflow Users Are Brilliant And Hard Working" | sed 's/\(.\{1,30\}\w*\)\(.*\)/\1/'
    

    这也适用于短于 30 个字符的文本 - 在这种情况下不会发生修剪。

    说明

    这是我开始使用的正则表达式:

    .{1,30}\w*
    

    它只是获取 1-30 个字符,然后是紧随其后的所有其他单词字符。

    现在为了能够在 sed 中使用它,我们必须去掉我们需要两个组的所有其他内容:

    (.{1,30}\w*)(.*)
    

    现在对 '()' 和 '{}' 进行一些转义:

    \(.\{1,30\}\w*\)\(.*\)
    

    这可以去sed:

    sed 's/<pattern>/<replacement>/<flags>'
    

    我们要删除第二组,所以在 sed 中我们使用 '\1'(第一组)替换:

    echo "..." | sed 's/\(.\{1,30\}\w*\)\(.*\)/\1/'
    

    【讨论】:

    • 嘿帕维尔,是的!这就是我一直在寻找的。如果您可以为\(.\{1,30\}\w\+\)\(.*\)/\1 部分提供解释,我很乐意学习。否则,感谢您的帮助。我将在今天晚些时候标记最佳答案:-)
    • 有一个小错误,我编辑了答案。我会在几分钟内写一个解释。
    • 添加说明
    • 感谢您的解释。非常清晰易懂。我很欣赏这些知识 :-) 我相信这也会对其他人有所帮助。
    【解决方案5】:

    使用 bash

    var="StackOverflow Users Are Brilliant And Hard Working"
    echo ${var:0:30}
    

    或者

    expr substr "$var" 1 30
    

    【讨论】:

    • 不适合我...我得到输出:StackOverflow Users Are Brilli
    • 对不起,我知道你想在 30 字符后停止
    • 是的,但我需要包含 StackOverflow Users Are Brilliant 的其余部分。您的输出将Brilliant 削减为Brilli
    • 好的,使用 bash : var="StackOverflow 用户非常聪明且努力工作" var1=${var#*${var:0:30}} echo ${var%${var1#* }}
    【解决方案6】:

    使用 GNU awk 进行 gensub():

    $ awk '{$0=gensub(/(.{30}\S*).*/,"\\1",1)} 1' file
    StackOverflow Users Are Brilliant
    

    或 GNU sed:

    $ sed -E 's/(.{30}\S*).*/\1/' file
    StackOverflow Users Are Brilliant
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 2011-11-15
      • 1970-01-01
      相关资源
      最近更新 更多