【问题标题】:Extract Pattern Matches / Remove Everything From Line Except Pattern提取模式匹配/从行中删除除模式之外的所有内容
【发布时间】:2019-10-14 18:25:45
【问题描述】:

我目前正在使用 grep 尝试从文件的每一行中提取特定文本。它成功地提取了匹配项,但是,我希望它保留任何没有匹配项的行(将它们保留为空行)。

这是我迄今为止尝试过的(获取每行的城市名称):

grep -o -P '(?<="city":").*?(?=")' input.txt

示例输入:

email":"addictedtotlick7@gmail.com","last_name":"THOMPSON","first_name":"ERIN",,"__v":0,,,,"state":"NY","city":"north tonawanda"}
first_name":"chris","last_name":"caul",,"email":"dawgzn@mail.com",,,,"__v":0}
email":"lesliebo993@hotmail.com",,"first_name":"LESLIE","last_name":"RAMBO",,"city":"DOTHAN","state":"AL",,,"__v":0,
email":"malala@yahoo.com",,,"state":"GA","city":"NORCROSS",,"last_name":"KEO","first_name":"CATHY",,"__v":0,
email":"kdela@gmail.com",,"state":"FL","city":"HOLLYWOOD",,"last_name":"DE LA CRUZ","first_name":"KIDA",,"__v":0,

期望的输出:

north tonawanda

DOTHAN
NORCROSS
HOLLYWOOD

很高兴在 SED 中尝试一些东西,如果它更容易的话,但我宁愿避免使用 AWK,因为我必须处理大文件,不确定我是否有足够的 RAM。

【问题讨论】:

  • grep 似乎会丢弃空匹配项。
  • 你有 GNU awk 吗?试试gawk '{print index($0, "\"city\":\"") == 0 ? "" : gensub(/.*\"city\":\"([^\"]*).*/, "\\1", $0);}' file &gt; newfile
  • @WiktorStribiżew - 当我运行它时,这似乎产生了正确的输出,但我在控制台中为每一行得到了这个:gawk: cmd. line:1: (FILENAME=db1.txt FNR=100000) 警告:gensub:第三个参数`email":"uccelds@cox.net",,"__v":0,,,"state":"CT"," city":"Rocky Hill","last_name":"Uccello","first_name":"Sebastiano"}' 视为 1
  • 好的,知道了。发帖。

标签: csv awk sed grep


【解决方案1】:

您可以使用 GNU awk

gawk '{print index($0, "\"city\":\"") == 0 ? "" : gensub(/.*\"city\":\"([^\"]*).*/, "\\1", 1);}' file > newfile

这意味着:如果行中有"city":" (index($0, "\"city\":\"") == 0) 则 (?) 打印一个空行 ("") 或 (:) 打印 gensub(/.*\"city\":\"([^\"]*).*/, "\\1", 1) 正则表达式的结果替换:

  • .* - 任何 0+ 个字符
  • \"city\":\" - "city":" 子字符串
  • ([^\"]*) - 捕获组 1 (\1):除 " 之外的任何 0+ 个字符
  • .* - 任何 0+ 个字符。

结果是组 1 的值。我们需要 gensub,因此需要 GNU awk,因为我们需要访问捕获组的值。

【讨论】:

    【解决方案2】:

    我建议另一个 awk 脚本

    awk 'match($0,/(?<=\"city\":\").*?(?=\")/,m){$0=m[0]}1' input.txt
    

    RAM 和 awk 没有问题。

    此脚本处理每一行。 如果当前行匹配正则表达式(?&lt;="city":").*?(?="),则用匹配覆盖当前行。打印当前行。

    【讨论】:

      【解决方案3】:

      Sed:

      sed 's/.*city":"\([^"]*\).*/|\1/; /^[^|]/s/.*//; s/^|//'
      

      【讨论】:

      • 而且,说到大文件,sed 也快得多。
      【解决方案4】:

      你可以试试 Perl

      $ perl -nle ' if(/"city":"(.*?)"/) { print $1 } else { print "" } ' input.txt
      north tonawanda
      
      DOTHAN
      NORCROSS
      HOLLYWOOD
      
      $
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-01-30
        • 2012-03-06
        • 1970-01-01
        • 1970-01-01
        • 2021-05-26
        • 2022-08-21
        相关资源
        最近更新 更多