我在简化 sed 语法以向数字组织方案添加不同数量的前导零时遇到困难。我正在操作的字符串看起来像
1.1.1.1,Some Text Here
利用 sed 语法
sed -r ":r;s/\b[0-9]{1,$((1))}\b/0&/g;tr"
我能够引起回应
01.01.01.01,Some Text Here
但是,我正在寻找的是在字段 2 和 3 中最多填充 2 位数字以及在字段 4 中填充最多 3 位数字的内容,以便所有项目都具有 [0-9] 的标准长度。[0-9]{ 2}.[0-9]{2}.[0-9]{3}
1.01.01.001,Some Text Here
对于我的一生,我什至不知道如何修改边界以包含仅捕捉句点后的数字所需的参数。我认为这与使用 \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
此外,如果该语句包含以下文本,我预计还会遇到其他问题:
1.1.1.1,Some Number 1 Here
我需要真正学习 sed 及其所有复杂性,这已成定局。我正在努力解决这个问题,但预计这个特定的声明将继续给我带来一段时间的麻烦。任何帮助将不胜感激。
编辑:我找到了一种方法...这个语句似乎符合我的要求,但必须有一种更优雅的方法来做到这一点。
sed -r ':r;s/\b[0-9]{1,1}\.\b/0&/;tr;:i;s/\b[0-9]{1,2},\b/0&/;ti;s/.//'
另外,从语法上讲,如果文本中出现类似的数字格式,这将导致问题...类似于:
1.1.1.1,Some Text Referring to Document XXX Heading 1.2.3
在这种情况下,将会导致:
1.01.01.001,Some Text Referring to Document XXX Heading 01.02.03
解决了 在此感谢大家的帮助。我最初用下面接受的答案解决了问题。我感觉将该解决方案转移到 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)
答案1
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
1.01.01.001,Some Text Here
答案2
您没有特别要求解决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"'
其结果:
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
这是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
答案3
用法: 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"
解释:
- 第一次替换为每个数字添加一定数量的零。 1 个零到 2 和 3 个数字,2 个零到 4 个数字。已经有多少位数并不重要。
- 第二次替换删除所有多余的零,只留下所需数量的数字。 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
输出.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
答案4
perl -pe '/^\d/g && s/\G(?:(\.\K\d+(?=\.))|\.\K\d+(?=,))/sprintf "%0".($1?2:3)."d",$&/ge'
解释:
这里使用的方法是查看数字的邻域并据此采取行动。因此,第二个和第三个数字的两侧都有一个点,而第四个数字的左侧有一个点,右侧有一个逗号。
当正则表达式采用第二个或第三个数字的路径时设置 $1,因此精度填充为 2。OTOH,对于第四个数字,填充为 3。
% cat 文件.txt
1.00.3.4,Some Text Here
1.01.01.1,Some Text Here
1.0.01.1,Some Number 1 Here
1.1.1.1,Some Text Referring to Document XXX Heading 1.2.3.4
1.2.3.4,Some \n \s \text
结果:
1.00.03.004,Some Text Here
1.01.01.001,Some Text Here
1.00.01.001,Some Number 1 Here
1.01.01.001,Some Text Referring to Document XXX Heading 1.2.3.4
1.02.03.004,Some \n \s \text