【问题标题】:Parsing plain text with AWK regex tools使用 AWK 正则表达式工具解析纯文本
【发布时间】:2013-06-23 03:15:57
【问题描述】:

我有一道印尼物理题:

Dari salah satu bagian gedung yang tingginya 20 m, dua buah batu dijatuhkan secara berurutan。 Massa kedua batu masing-masing 1/2 公斤丹 5公斤。 Bila percepatan gravitasi bumi di tempat itu g = 10 m/s2, tentukan waktu jatuh untuk kedua batu itu (Abaikan gesekan udara)

英文翻译如下(来自Google Translate):

从一栋 20 m 高的建筑物中掉落了两块石头。 第二块石料各1/2公斤和5公斤。如果加速度 g = 10 m/s2 处的重力,确定它下降到秒的时间 石头(忽略空气摩擦)

我想把这个问题解析成这种形式:

Height = 20 m
Mass A = 1/2 kg 
Mass B = 5 kg
Gravity = 10 m/s2

到目前为止,我只有两种形式的代码。这是第一个:

#只取数字

{
  for(i=1; i<=NF; i++){          
    if($i ~ /^[[:digit:]]+/)       
    print $i                 
  }
}

#只取单位

{  
  for(i=1; i<=NF; i++){                     
  if(($i ~ /^m\/s2/) || ($i ~ /^kg$/) || ($i ~ /^m$/))      
      print $i  
  }
}

现在,如何加入这两个 awk 代码?我做了这样的联合:

BEGIN { FS = "[, ]+" }  

#taking units

{  
  for(i=1; i<=NF; i++){                     
  if(($i ~ /^m\/s2/) || ($i ~ /^kg$/) || ($i ~ /^m$/))      
      print $i                                  
  }
}

#taking numbers

{
  for(i=1; i<=NF; i++){          
    if($i ~ /^[[:digit:]]+/) 
      print $i              
  }
}

但是上面的代码会产生这个输出:

master@master:~/Dokumen/Pelajaran/Semester 4/Pak Anom$ awk -f plasma.awk soal1 
m
20
kg
m/s2
1/2
5
10
master@master:~/Dokumen/Pelajaran/Semester 4/Pak Anom$ 

至少,我希望结果是这样的:

20 m
1/2 kg 
5 kg 
10 m/s2

我想使用这个 awk 代码作为体育锻炼/问题自动计算的基础,所以这个基础对我来说非常重要。有什么建议吗?谢谢你。

【问题讨论】:

  • 我不完全相信印度尼西亚物理问题解析器可能对编程社区普遍有用:-)
  • @DannyBee: regex 很好,但是当 OP 说他想使用 awk 时,为什么还要继续添加 perlsed 标签?

标签: regex parsing awk


【解决方案1】:

你可以试试这样的:

awk '{
    for(i=1;i<=NF;i++) {
        gsub(/[,.]/,"",$(i+1))
        if($i~/^[[:digit:]]/) {
            print $i,$(i+1)
        }
    }
}' file

测试:

$ cat file
Dari salah satu bagian gedung yang tingginya 20 m, dua buah batu dijatuhkan secara berurutan. Massa kedua batu masing-masing 1/2 kg dan 5 kg. Bila percepatan gravitasi bumi di tempat itu g = 10 m/s2, tentukan waktu jatuh untuk kedua batu itu (Abaikan gesekan udara)

$ awk '{
    for(i=1;i<=NF;i++) {
        gsub(/[,.]/,"",$(i+1))
        if($i~/^[[:digit:]]/) {
            print $i,$(i+1)
        }
    }
}' file
20 m
1/2 kg
5 kg
10 m/s2

更新:添加更多if 条件以获得您想要的结果

$ awk '{
    for(i=1;i<=NF;i++) {
        gsub(/[,.]/,"",$(i+1))
        if($i~/^[[:digit:]]/ && $(i+1)=="m") {
            print "Height = "$i,$(i+1)
        }
        else if($i~/^[[:digit:]]/ && $(i+1)=="kg") {
            print "Mass "++x" = "$i,$(i+1)
        }
        else if($i~/^[[:digit:]]/ && $(i+1)=="m/s2") {
            print "Gravity = "$i,$(i+1)
        }
    }
}' file
Height = 20 m
Mass 1 = 1/2 kg
Mass 2 = 5 kg
Gravity = 10 m/s2

【讨论】:

  • 非常感谢。一切都在几秒钟内解决!惊人的。 gsub是什么意思?简而言之,创建此代码的逻辑是什么?我想了 3 周,但我的结果只是我的第一个问题。
  • 不客气。 gsub 在内置的 awk 函数中,允许您进行替换。顾名思义,gsub 中的g 是进行多次替换。我添加了该部分,因为有,. 附加到我们的字段(例如m,20 m)。这有助于从您的输出中删除它。
  • 使用的逻辑是,以数字开头的每个字段都是我们假设的捕获,而数字后面的每个文本都是该数字的度量。因此,使用for loop,我们遍历了每个字段并捕获了一个带有数字的字段,下一个假设它是公制的。
  • 感谢您的解释。实际上,我在第一次尝试时创建了与您在上面给出的类似的代码,使用 for。但我失败了,所以你帮助了我。在管理员关闭此线程之前,如何为您提供声誉?我是 Stackoverflow 的新手。
【解决方案2】:

GNU 代码

BEGIN { FS = "[ .,]"}
      {
            for (i = 1; i <= NF; i++) {
                 if ($i ~ /[0-9]/){
                    print($i, $(++i))
                    }
                }
            }

$awk -f a.awk 文件 20米 1/2 公斤 5公斤 10米/秒2

【讨论】:

  • 谢谢,您使用 FS 声明而不是 gsub() 函数。这是一个很好的选择。我接受你的解决方案。
猜你喜欢
  • 2016-04-27
  • 2015-10-10
  • 1970-01-01
  • 1970-01-01
  • 2012-05-18
  • 2013-08-13
相关资源
最近更新 更多