【问题标题】:Retrieve last and next pattern after finding a pattern找到模式后检索上一个和下一个模式
【发布时间】:2016-11-16 02:45:43
【问题描述】:

过去 2-3 天我一直在谷歌搜索和搜索解决方案,但我似乎找不到任何解决方案。

基本上,我有一个包含数十万条记录的文本文件。这是文件中包含的内容的模式。

  • 01 行:^D 23554
  • 02 行:Q 123 325
  • 第 03 行:Y qwe325
  • 第 04 行:^P fiwkkwlds
  • 第 05 行:Y qrwe
  • 第 06 行:Y rtewt
  • 07 行:^A 284274 DFL 2939955 001
  • 08 行:F 2739
  • 第 09 行:^D 23556
  • 第 10 行:^k 2994
  • 第 11 行:^A 284274 DFL 2939966 002
  • 第 12 行:^k 29942
  • 第 13 行:^k 32423
  • 第 14 行:^A 284274 DFL 2939957 003
  • 第 15 行:F 23425
  • 第 16 行:^A 284274 DFL 2939958 004
  • 第 17 行:F 92823
  • 第 18 行:依此类推...

基本上,数据中没有特定的模式,但是每行的开头 --> ^D、Q、Y、^P、^A、F、^k 代表一个简单的消息。

我正在寻找一个脚本(最好是在 shell、perl 或 c++ 中),它将从第一行到最后一行扫描文件,并且

1) 检索 ^A 行中的所有值 2) 插入分隔符 3) 检索 ^D 行中的最后一个值 4) 插入分隔符 5) 检索 F 行中的下一个值 6)希望,用数据创建另一个文本文件

根据我之前的例子,下面是结果:

  • 01 行:284274 DFL 2939955 001|23554|2739
  • 02 行:284274 DFL 2939966 002|23556|23425
  • 03 行:284274 DFL 2939957 003|23556|23425
  • 04行:284274 DFL 2939958 004|23556|92823

换句话说:

来自 ^A 行的值 |上一个^D行的值|来自下一个 F 行的值。

有人可以帮助我吗?我一直在阅读有关哈希图和哈希表的信息,但我不太确定如何使用它们。我已经看到了很多使用 grep 的解决方案,您可以在其中找到一个模式 ex: ^A 并打印该模式之前/之后的最后 x 行,但是,由于该数据可能是超级随机的,因此前一个 ^D 消息或下一个 F 消息可以在任何线路上。

解决方案必须读取文件并始终将 ^D 和 F 行值保存在内存中,并在找到模式 ^A 时检索它们。

谁能帮帮我:)

谢谢!!!!

【问题讨论】:

  • 向我们展示您的代码。到目前为止,您尝试过什么?
  • 嗨易卜拉欣。我并没有真正编写任何代码,因为我不确定该怎么做。我使用 grep 进行了一些测试,以从 ^A、^D 和 F 行检索内容(在单独的文件中),但没什么。我正在考虑将文件导入 SQL 数据库并尝试找到解决方案,但我认为这对我没有多大帮助。你有什么建议吗?谢谢!

标签: c++ regex shell hashmap pattern-matching


【解决方案1】:

这是伪代码:

d_value = f_value = null
foreach line in input {
  if line matches ^A {
    print line | d_value | f_value
    d_value = f_value = null
  }
  else if line matches ^D
    a_value = <extracted value>
  else if line matches ^F
    f_value = <extracted value>
}

它假定 d 和 f 值在 a 之前。您可以添加错误检查以确保值存在。

希望对您有所帮助。

【讨论】:

    【解决方案2】:

    试试这个正则表达式:

    (?<=\^A\s)(?<a>\V+)|(?<=\^D\s)(?<b>\V+)|(?<=\F\s)(?<c>\V+)
    

    它将^A 值作为组(a),^D 值作为组(b),F 值作为组(c)。

    匹配这些值后,您可以轻松地在此 Regex 上构建,以使用您选择的任何编程语言对它们进行排序。

    演示:https://regex101.com/r/2tipn0/1

    【讨论】:

    • 嗨易卜拉欣。我尝试将此正则表达式与 grep 一起使用,但我似乎不知道如何使其工作。我尝试了 grep -n '^\^A' file.txt 但检索以 ^A 开头的行。我也试过 grep -n -C1 '^\^A' file.txt 这给了我模式前后的行。
    【解决方案3】:

    这个可行,但我认为大文件应该很慢:

    IFS=$'\n'
    readarray -t -O1 data< <(grep -h -e "\^D" -e "\^A" -e "^F" a.txt)
    posA=1
    for i in "${data[@]}"; do
    if [[ "$i" = "^A"* ]]; then
        textA="${data[$posA]}"
        posD=$posA
        posF=$posA
        textD=""
        textF=""
        while [ "$posD" -ge 1 ] && [[ "$textD" != "^D"* ]]; do
        posD=$(($posD - 1))
        textD="${data[$posD]}"
        done
    
        while [ "$posF" -le "${#data[@]}" ] && [[ "$textF" != "F"* ]]; do
        posF=$(($posF + 1))
        textF="${data[$posF]}"
        done
        textADF="$textA | $textD | $textF"
        echo "ADF=$textADF"
    fi
    posA=$(($posA + 1))
    done
    unset IFS
    exit
    

    整个实现基于

    的输出
    grep -h -e "\^D" -e "\^A" -e "^F" a.txt
    

    它被存储到一个数组“数据”中,然后代码操作这个数组,事实上while循环将在第一次匹配时停止。

    也许您可以将上面的 grep 与 head 和 tail 结合起来以避免数组操作。

    PS1:对 grep 也应用 -n 开关会提供有趣的输出。

    PS2:我无法使用“^A ^D F”组直接 grep 文件以避免使用代码进行数组操作,但使用正则表达式可能会做到这一点。

    【讨论】:

    • 乔治,你就是男人!!!该脚本运行良好,老实说速度非常快。我在较大的文本文件上对其进行了测试。非常感谢!你不明白这有多大帮助。真的很感谢你的努力!竖起大拇指!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-21
    • 2013-10-23
    • 1970-01-01
    • 1970-01-01
    • 2014-05-21
    相关资源
    最近更新 更多