实现扩展的正则表达式以根据字符串中的位置添加可变数量的前导零

dai*_*zai 10 sed regular-expression

我在降低 sed 语法以将不同数量的前导零添加到数字组织方案时遇到了麻烦。我正在操作的字符串看起来像

1.1.1.1,Some Text Here
Run Code Online (Sandbox Code Playgroud)

利用 sed 语法

sed -r ":r;s/\b[0-9]{1,$((1))}\b/0&/g;tr"
Run Code Online (Sandbox Code Playgroud)

我能够引起反应

01.01.01.01,Some Text Here
Run Code Online (Sandbox Code Playgroud)

但是,我正在寻找的是将字段 2 和 3 中的最多 2 位数字和字段 4 中的 3 位数字填零,以便所有项目在 [0-9].[0-9]{ 处具有标准长度。 2}.[0-9]{2}.[0-9]{3}

1.01.01.001,Some Text Here
Run Code Online (Sandbox Code Playgroud)

在我的一生中,我什至无法弄清楚如何修改边界以包含仅捕捉到句点后的数字所必需的参数。我认为这与使用 \b 有关,我理解它在单词边界匹配零个字符,但我不明白为什么我尝试在匹配中添加句点失败,如下所示:

sed -r ":r;s/\.\b[0-9]{1,$((1))}\b/0&/g;tr"
sed -r ":r;s/\b\.[0-9]{1,$((1))}\b/0&/g;tr"
Both cause the statement to hang

sed -r ":r;s/\b[0-9]\.{1,$((1))}\b/0&/g;tr"
sed -r ":r;s/\b[0-9]{1,$((1))}\.\b/0&/g;tr"
sed -r ":r;s/\b[0-9]{1,$((1))}\b\./0&/g;tr"
cause the statement to output:

1.01.01.1,Some Text Here
Run Code Online (Sandbox Code Playgroud)

此外,如果语句包含以下文本,我希望我会遇到其他问题:

1.1.1.1,Some Number 1 Here
Run Code Online (Sandbox Code Playgroud)

众所周知,我需要真正学习 sed 及其所有复杂性。我正在努力解决这个问题,但预计这个特殊的声明会继续给我带来一段时间的麻烦。任何帮助将不胜感激。

编辑:我想出了一种方法......这个语句似乎做我正在寻找的东西,但必须有一种更优雅的方式来做到这一点。

sed -r ':r;s/\b[0-9]{1,1}\.\b/0&/;tr;:i;s/\b[0-9]{1,2},\b/0&/;ti;s/.//'
Run Code Online (Sandbox Code Playgroud)

此外,如果文本中出现类似的数字格式,这在语法上会导致问题......类似于:

1.1.1.1,Some Text Referring to Document XXX Heading 1.2.3
Run Code Online (Sandbox Code Playgroud)

在这种情况下,它将导致:

1.01.01.001,Some Text Referring to Document XXX Heading 01.02.03
Run Code Online (Sandbox Code Playgroud)

已解决 谢谢大家的帮助。我最初用下面接受的答案解决了这个问题。我感觉将解决方案移到 Python 中,作为利用以下排序的更大解决方案的一部分:

def getPaddedKey(line):
    keyparts = line[0].split(".")
    keyparts = map(lambda x: x.rjust(5, '0'), keyparts)
    return '.'.join(keyparts)

s=sorted(reader, key=getPaddedKey)
Run Code Online (Sandbox Code Playgroud)

gle*_*man 9

bash 可以处理这个。不过它会比 perl 慢很多:

echo "1.1.1.1,Some Text Here" | 
while IFS=., read -r a b c d text; do
    printf "%d.%02d.%02d.%03d,%s\n" "$a" "$b" "$c" "$d" "$text"
done
Run Code Online (Sandbox Code Playgroud)
1.01.01.001,Some Text Here
Run Code Online (Sandbox Code Playgroud)

  • 或 awk。但是+1 使用`printf`,明智的工具。(Awk 也有 `printf`,并且在文本处理方面比 `bash` 设计得更好。)另请参阅 [为什么使用 shell 循环来处理文本被认为是不好的做法?](http://unix.stackexchange.com/q/ 169716/135943) (2认同)

roa*_*ima 5

您没有特别要求perl解决方案,但无论如何这里有一个。我个人认为这更容易阅读,尤其是当分成几行时。

首先是单行:

(
    echo '1.2.3.4,Some Text Here'
    echo '1.01.01.1,Some Text Here'
    echo '1.1.1.1,Some Number 1 Here'
    echo '1.1.1.1,Some Text Referring to Document XXX Heading 1.2.3'
    echo '1.2.3.4,Some \n \s \text'
) |
perl -ne '($ip, $text) = split(/,/, $_, 2); $ip = sprintf("%1d.%02d.%03d.%03d", split(/\./, $ip)); print "$ip,$text"'
Run Code Online (Sandbox Code Playgroud)

其结果:

1.02.003.004,Some Text Here
1.01.001.001,Some Text Here
1.01.001.001,Some Number 1 Here
1.01.001.001,Some Text Referring to Document XXX Heading 1.2.3
1.02.003.004,Some \n \s \text
Run Code Online (Sandbox Code Playgroud)

这是perl分解并注释的脚本(该-n标志while read; do ... done在代码周围放置了一个隐式循环):

($ip, $text) = split(/,/, $_, 2);                # Split line into two parts by comma
@octets = split(/\./, $ip)                       # Split IP address into octets by dots
$ip = sprintf("%1d.%02d.%03d.%03d", @octets);    # Apply the formatting
print "$ip,$text"                                # Output the two parts
Run Code Online (Sandbox Code Playgroud)


Min*_*Max 4

用法: leading_zero.sh input.txt

#!/bin/bash

sed -r '
    s/\.([0-9]{1,2})\.([0-9]{1,2})\.([0-9]{1,3},)/.0\1.0\2.00\3/
    s/\.0*([0-9]{2})\.0*([0-9]{2})\.0*([0-9]{3})/.\1.\2.\3/
' "$1"
Run Code Online (Sandbox Code Playgroud)

解释:

  1. 第一次替换为每个数字添加一定数量的零。1 个零到 2 和 3 个数字,2 个零到 4 个数字。已经有多少位数并不重要。
  2. 第二次替换删除所有多余的零,只留下所需数量的数字。2 和 3 数字应仅包含 2 位数字。留下它们并删除休息。第四个数字只能包含 3 位数字。留下它们并删除休息。

输入.txt

1.1.1.1,Some Text Here
1.1.1.1,Some Text Here
1.11.1.11,Some Text Referring to Document XXX Heading 1.2.3
1.1.1.1,Some Text Here
1.1.11.111,Some Text Referring to Document XXX Heading 1.2.3
1.11.1.1,Some Text Here
Run Code Online (Sandbox Code Playgroud)

输出.txt

1.01.01.001,Some Text Here
1.01.01.001,Some Text Here
1.11.01.011,Some Text Referring to Document XXX Heading 1.2.3
1.01.01.001,Some Text Here
1.01.11.111,Some Text Referring to Document XXX Heading 1.2.3
1.11.01.001,Some Text Here
Run Code Online (Sandbox Code Playgroud)