繁体   English   中英

bash,awk和或sed以特殊格式清除字符串

[英]bash, awk and or sed to clean up string with special formatting

在我正在处理的脚本中,我必须将字符串清理为所需的格式。

每个字符串的结构:(邮政编码,街道名称,号码,扩展名):

  • 4位数字,2个字母(邮政编码)如果不匹配,则没有结果
  • 字符串(街道名称)可以有任何类型的字符
  • 一串数字(数字)

最终被

  • 字符串(扩展名)可以具有任何类型的字符,并且并不总是存在。 如果是数字,则用破折号,空格或其他东西将其与数字分隔开

结果字符串应为4位数字,2个字母,数字,并在扩展名的情况下后跟x和扩展名的字母或数字

下面是一些示例:

  • 1019RX Javakade 254 -result:1019RX254
  • 1019PG Bogortuin 50-结果: 1019PG50
  • 1079TH Eemsstraat 34 - II-结果: 1079TH34xII
  • 1066EC 1eLouwesweg6-结果: 1066EC6
  • 1019LC KNSM-laan193-结果: 1019LC193
  • 1019WZ Scheepstimmermanstraat 74 -result:1019WZ74
  • 2288EA SirWinstonChurchillaan 275 - F126 -result:2288EA275xF126
  • 1056HZ MaartenHarpertszoonTrompstraat 12 - 3hg -result:1056HZ12x3hg
  • 1092GR Laing'snekstraat 15G -result:1092GR15xG
  • F-30700RueduLavoir1-结果:

我开始

echo "1019RXJavakade254" | awk '{print substr($0,0,6)}'

要获取邮政编码,然后我应该使用“打印匹配”,但是我无法从那里获取它。

这些字符串将分别传递并在脚本的下一步中使用。 最初它们来自csv文件,但是字符串来自的(组合)列始终是不同的。 脚本的第一部分是处理并创建此源字符串。 结果字符串将放回到一列中,我可以将其作为最后一列添加到原始csv文件中

我知道有关前6个字符后的数字以及是否存在扩展名的问题。 因此,我认为工作流程应类似于:前6个字符应为4位数字,2个字母,如果不是总结果为空。 跳过字符7和8,获取在字符8之后遇到的第一组数字,即数字,其后的所有其他内容均为扩展名。 该扩展名永远不会直接以数字开头。 仅在扩展名之间存在x。 该扩展名应去除其他字母数字字符。

这应该涵盖最多,其余的将延迟交货:)


解决了

@kvantour感谢您的回答。 我也稍微更改了代码以获取非大写字母。 结果是更大的applescript的一部分,该applescript在公司的Xserve上无人值守。 所以我现在使用的代码是

set KixCodeSourceClean to do shell script "echo " & KixCodeSource & " | awk '/^[0-9]{4}[a-zA-Z]{2}.+[0-9]+[- ].+$/{match(substr($0,8),/[0-9]+[- ].+$/);s=substr($0,7+RSTART,RLENGTH); sub(/[- ]/,\"x\",s);print substr($0,1,6)s;next} /^[0-9]{4}[a-zA-Z]{2}.+[0-9]+[a-zA-Z].*$/{match(substr($0,8),/[0-9]+[a-zA-Z].*$/);s=substr($0,7+RSTART,RLENGTH);match(s,/[0-9]+/);print substr($0,1,6)substr(s,1,RLENGTH)\"x\"substr(s,RLENGTH+1);next} /^[0-9]{4}[a-zA-Z]{2}.+[0-9]+$/{ match(substr($0,8),/[0-9]+$/);s=substr($0,7+RSTART);print substr($0,1,6)s;next}'"

它完美地工作并且是一个一体式,在这种情况下,我更喜欢。 我经常使用这种方法。 跳出Applescript并使用unix shell更快地解决问题。

提取邮政编码和扩展名的几项要求,因此将结果流水线传输到其他sed此处。

$ str="1066EC1eLouwesweg6"
$ sed -r 's/(^[0-9]{4}[A-Z]{2})..[^0-9]*(.*)/\1\2/' <<< "$str" | sed 's/-/x/' | sed -r '/[^x]/ s/(.*[0-9]+)([A-Z]+$)/\1x\2/'
1066EC6

简要说明,

  1. sed -r 's/(^[0-9]{4}[AZ]{2})..[^0-9]*(.*)/\\1\\2/' <<< "$str" :首先过滤掉街道名称。
  2. sed 's/-/x/' :如果存在,将'-'替换为'x'
  3. sed -r '/[^x]/ s/(.*[0-9]+)([AZ]+$)/\\1x\\2/' :如果到目前为止的结果不存在'x',在数字和字母之间添加“ x”。

我想到的想法是一种排除原则,我们在其中逐个测试一种可能性:

  1. 格式为NNNNXXabc123efgMMM-SUFNNNNXXabc123efgMMM SUF
  2. 格式为NNNNXXabc123efgMMMSUF地址
  3. 格式为NNNNXXabc123efgMMM地址

但是,问题在于SUF可以是任何东西,而abc123efg可以是任何东西。 结果,示例“ 1066EC1eLouwesweg6”将与第二种情况匹配。

为了避免这种情况,我当时想看看街道名称的条件,但是在荷兰,这些可以是任何东西:

  • 铱。 Heerlen的范·沃特肖特·范·德·格拉希斯特拉特先生 (长)
  • 奈梅韦根的玛格·克朗佩兰(MargaKlompélaan)格鲁特·布里坦尼斯特拉( Groot-Brittanniëstraat
  • 阿姆斯特丹的1e en 2e Anjeliers-dwarsstraat (从数字开始)
  • Winschoten的Sint Vitusholt 2e Laan (中间数字)
  • Hilversum中的's-Gravelandseweg (以'开头)
  • 奥托兰德的AB (太短了)

因此,街道名称的长度甚至没有限制,除非它是一个字符长,而是一个字母。

因此,这给了我以下AWK:

{gsub(/\r/,"",$0)}  # removes `\r` if any
/^[0-9][0-9][0-9][0-9][A-Z][A-Z].+[0-9]+[- ].+$/{match(substr($0,8),/[0-9]+[- ].+$/);s=substr($0,7+RSTART,RLENGTH); sub(/[- ]/,"x",s);print substr($0,1,6)s;next}
/^[0-9][0-9][0-9][0-9][A-Z][A-Z].+[0-9]+[a-zA-Z].*$/{match(substr($0,8),/[0-9]+[a-zA-Z].*$/);s=substr($0,7+RSTART,RLENGTH);match(s,/[0-9]+/);print substr($0,1,6)substr(s,1,RLENGTH)"x"substr(s,RLENGTH+1);next}
/^[0-9][0-9][0-9][0-9][A-Z][A-Z].+[0-9]+$/{ match(substr($0,8),/[0-9]+$/);s=substr($0,7+RSTART);print substr($0,1,6)s;next}

并在此输入文件上:

1019RXJavakade254
1019PGBogortuin50
1079THEemsstraat34-II
1066EC1eLouwesweg6
1019LCKNSM-laan193
1019WZScheepstimmermanstraat74
2288EASirWinstonChurchillaan275-F126
1056HZMaartenHarpertszoonTrompstraat12-3hg
1092GRLaing'snekstraat15G
F-30700RueduLavoir1

它给了我以下输出:

1019RX254
1019PG50
1079TH34xII
1066EC6
1019LC193
1019WZ74
2288EA275xF126
1056HZ12x3hg
1092GR15xG

如您所见,最后一个不匹配!

但是,我无法向您保证这将100%有效。

有趣的事实:在奥托兰,您可以跨过10m的桥梁从A到B行驶

(使用GNU awk将第三个arg match()match()gensub() )将从您提供的输入中产生预期的输出:

$ cat tst.awk
match($1,/^([0-9]{4}[[:alpha:]]{2})(..[^0-9]+)(.*)/,a) {
    if ( ! sub(/[^[:alnum:]]/,"x",a[3]) ) {
        a[3] = gensub(/([0-9])([[:alpha:]])/,"\\1x\\2",1,a[3])
    }
}
{
    tgt = (1 in a ? a[1] a[3] : "nothing")
    print tgt, (tgt == $NF ? "succ" : "fail")
}

$ awk -f tst.awk file
1019RX254 succ
1019PG50 succ
1079TH34xII succ
1066EC6 succ
1019LC193 succ
1019WZ74 succ
2288EA275xF126 succ
1056HZ12x3hg succ
1092GR15xG succ
nothing succ

如果数字可以出现在街道名称中的前两个字符以外的任何地方,则将失败。

上面的代码在此输入文件上运行,并根据结果是否与输入文件最后一个字段的预期结果相匹配,在每个结果之后输出succ / fail:

$ cat file
1019RXJavakade254 -result: 1019RX254
1019PGBogortuin50 -result: 1019PG50
1079THEemsstraat34-II -result: 1079TH34xII
1066EC1eLouwesweg6 -result: 1066EC6
1019LCKNSM-laan193 -result: 1019LC193
1019WZScheepstimmermanstraat74 -result: 1019WZ74
2288EASirWinstonChurchillaan275-F126 -result: 2288EA275xF126
1056HZMaartenHarpertszoonTrompstraat12-3hg -result: 1056HZ12x3hg
1092GRLaing'snekstraat15G -result: 1092GR15xG
F-30700RueduLavoir1 -result: nothing

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM