首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用bash、awk和sed清除具有特殊格式的字符串

使用bash、awk和sed清除具有特殊格式的字符串
EN

Stack Overflow用户
提问于 2018-07-24 08:10:35
回答 3查看 301关注 0票数 0

在我正在编写的脚本中,我必须将一个字符串清理成我需要的格式。

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

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

最后跟着

  • 字符串(扩展名)可以有任何类型的字符,但并不总是存在。当一个数字用破折号、空格或其他东西与数字分开时

得到的字符串应该是4个数字、2个字母、数字,如果是扩展名,则为x和扩展名的字母或数字。

以下是一些例子:

  • 1019RXJavakade254 -result:1019RX 254
  • 1019PGBogortuin50 -result:1019 PG50
  • 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-30700 RueduLavir1 -result:nothing

我一开始

代码语言:javascript
复制
echo "1019RXJavakade254" | awk '{print substr($0,0,6)}'

为了得到邮政编码,然后我想我应该使用“打印匹配”,但我无法从那里得到它。

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

我知道前6个字符之后的数字问题,以及是否存在扩展。所以在我看来,工作流应该是这样的:前6个字符应该是4个数字,2个字母,如果不是全部结果是空的。跳过字符7和8,获取在字符8之后遇到的第一组数字,即数字,后面的所有数字都是扩展名。扩展名从不直接以数字开头。只有在扩展的情况下,两者之间才有x。扩展部分应该去掉其他字母数字字符。

这应该涵盖的最多,其余的将有一个延迟交付:)

解出

@kvantour谢谢你的回答。我也稍微修改了代码以获得非大写字母。结果是一个更大的applescript的一部分,它在公司的Xserve上无人值守地运行。所以我现在使用的代码是

代码语言:javascript
复制
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更快地解决问题。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-07-24 09:51:12

我想到的是一个排除原则,在这个原则中,我们一个接一个地检验可能性:

  1. 表格NNNNXXabc123efgMMM-SUFNNNNXXabc123efgMMM SUF的地址
  2. 表格NNNNXXabc123efgMMMSUF的地址
  3. 表格NNNNXXabc123efgMMM的地址

然而,问题是SUF可以是任何东西,abc123efg可以是任何东西。因此,示例“1066EC1eLouwesweg 6”将与第二种情况匹配。

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

  • Ir。van Waterschoot van der Grachtstraat博士(刚刚长)
  • Marga Klompélaan和Groot-Brittanni straat在Nijmwegen (diacritics)
  • 1Een 2e Anjeliers-阿姆斯特丹的矮人(从数字开始)
  • Winschoten中的Sint Vitusholt 2e Laan (中间数字)
  • Hilversum中的Gravelandseweg(从'开始)
  • A和B在奥托兰(太短)

因此,街道名称的长度甚至没有任何条件,除非,如果它是一个字符长,它是一个字母。

这给了我以下AWK:

代码语言:javascript
复制
{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}

在这个输入文件上:

代码语言:javascript
复制
1019RXJavakade254
1019PGBogortuin50
1079THEemsstraat34-II
1066EC1eLouwesweg6
1019LCKNSM-laan193
1019WZScheepstimmermanstraat74
2288EASirWinstonChurchillaan275-F126
1056HZMaartenHarpertszoonTrompstraat12-3hg
1092GRLaing'snekstraat15G
F-30700RueduLavoir1

它给了我以下输出:

代码语言:javascript
复制
1019RX254
1019PG50
1079TH34xII
1066EC6
1019LC193
1019WZ74
2288EA275xF126
1056HZ12x3hg
1092GR15xG

正如你注意到的,最后一个是不匹配的!

然而,我不能向你保证,这将是百分之百的工作。

有趣的事实:在奥特兰,你可以通过一座10米的桥从A到B的旅行

票数 1
EN

Stack Overflow用户

发布于 2018-07-24 09:39:21

这里需要提取邮政编码和扩展,因此需要将结果传输到附加的sed

代码语言:javascript
复制
$ 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}[A-Z]{2})..[^0-9]*(.*)/\1\2/' <<< "$str":先过滤出街道名称。
  2. sed 's/-/x/':如果存在,将“-”替换为“x”
  3. sed -r '/[^x]/ s/(.*[0-9]+)([A-Z]+$)/\1x\2/':如果结果到目前为止还不存在“x”,那么在数字和字母之间添加“x”。
票数 1
EN

Stack Overflow用户

发布于 2018-07-24 11:51:26

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

代码语言:javascript
复制
$ 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/ file:

代码语言:javascript
复制
$ 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
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51493631

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档