bash - bash、awk 和/或 sed 清理具有特殊格式的字符串
问题描述
在我正在处理的脚本中,我必须将字符串清理为我需要的格式。
每个字符串的结构:(邮政编码、街道名称、号码、扩展名):
- 4 位数字,2 个字母(邮政编码) 如果不匹配,则无结果
- 字符串(街道名称)可以有任何类型的字符
- 一串数字(数字)
最终紧随其后
- 字符串(扩展名)可以有任何类型的字符,但并不总是存在。如果是数字,则用破折号、空格或其他东西将其与数字隔开
结果字符串应为 4 位数字、2 个字母、数字,如果是扩展名,则后跟 x 和扩展名的字母或数字
下面是一些例子:
- 1019RX Javakade 254 -结果:1019RX254
- 1019PG Bogortuin 50 -结果:1019PG50
- 1079TH Eemsstraat 34 - II -结果:1079TH34xII
- 1066EC 1eLouwesweg6 -结果:1066EC6
- 1019LC KNSM-laan193 -结果:1019LC193
- 1019WZ Scheepstimmermanstraat 74 -结果:1019WZ74
- 2288EA SirWinstonChurchillaan 275 - F126 -结果:2288EA275xF126
- 1056HZ MaartenHarpertszoonTrompstraat 12 - 3hg -结果:1056HZ12x3hg
- 1092GR Laing'snekstraat 15G -结果:1092GR15xG
- F-30700RueduLavoir1 -结果:没有
我从
echo "1019RXJavakade254" | awk '{print substr($0,0,6)}'
获取邮政编码,然后我认为我应该使用“打印匹配”,但我无法从那里得到它。
字符串单独传递并在脚本的下一步中使用。最初它们来自 csv 文件,但字符串来自的列(组合)总是不同的。脚本的第一部分正在处理它并创建这个源字符串。生成的字符串将放回一列中,我可以将其作为最后一列添加到原始 csv 文件中
我知道关于前 6 个字符之后的数字以及是否存在扩展名的问题。所以在我看来,工作流程应该是这样的:前 6 个字符应该是 4 个数字,2 个字母,如果不是总结果是空的。跳过字符 7 和 8 并抓住字符 8 之后遇到的第一组数字,即数字,之后的所有其他数字都是扩展名。扩展永远不会直接以数字开头。只有在扩展的情况下,两者之间才有一个 x。扩展名应去除其他字母数字字符。
这应该涵盖最多,其余的将有延迟交付:)
解决了
@kvantour感谢您的回答。我也稍微更改了代码以获取非大写字母。结果是一个更大的 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
简要说明,
sed -r 's/(^[0-9]{4}[A-Z]{2})..[^0-9]*(.*)/\1\2/' <<< "$str"
: 先过滤掉街道名称。sed 's/-/x/'
: 如果存在,将 '-' 替换为 'x'sed -r '/[^x]/ s/(.*[0-9]+)([A-Z]+$)/\1x\2/'
:如果到现在为止的结果不存在'x',则在数字和字母之间添加'x'。
推荐阅读
- typescript - 如何模拟“T extends enum”通用约束?
- aurelia - 使用 router.navigateToRoute() 导航到子路由
- php - PHP - mysqli 从本地主机(我的本地 PC)连接到亚马逊 EC2 托管数据库
- python - 从不同文件夹中的图像创建 numpy 数组
- reactjs - 动画反应弹簧(使用钩子与渲染道具)
- docker - Kubernetes中服务之间的连接问题
- vb.net - 如何将日期添加到数组中?
- c# - 使用联合服务从 ASP Web 应用程序注销时出现问题
- node.js - Multer 无法接收 req.file 中的文件名
- specflow - 我可以让 BeforeScenario 和 AfterScenario 挂钩中的场景失败吗?