Glu*_*ate 11 sed awk text-processing
我正在寻找一种方法来打印字符串中最长的数字。
例如:如果我有字符串
212334123434test233
Run Code Online (Sandbox Code Playgroud)
我怎样才能打印
212334123434
Run Code Online (Sandbox Code Playgroud)
?
注意:我正在寻找最长的连续数字序列,而不是数字更高的值。
编辑:谢谢大家的回答。对这个问题的回答是相当压倒性的。我将@HaukeLaging 的帖子标记为已接受的答案,因为它非常适合我的具体情况,但我想指出所有答案都同样有效。有几种不同的选择来解决问题总是很好。
slm*_*slm 13
我相信你可以做到这一点只是grep
,sort
和tail
也。下面是一些示例字符串。
$ echo <str> | grep -oP "\d+" | sort -n | tail -1
Run Code Online (Sandbox Code Playgroud)
<str>
我们的字符串在哪里?
$ set -o posix; set | grep "str[0-9]"
str0=212334123434test233
str1=212334123434test233abc44
str2=233test212334123434
str3=a212334123434test233abc44
str4=a91234b212334123434abc
Run Code Online (Sandbox Code Playgroud)
现在,如果我grep ...
依次通过我的命令运行这些。
$ echo $str0 | grep -oP "\d+" | sort -n | tail -1
212334123434
$ echo $str1 | grep -oP "\d+" | sort -n | tail -1
212334123434
$ echo $str2 | grep -oP "\d+" | sort -n | tail -1
212334123434
$ echo $str3 | grep -oP "\d+" | sort -n | tail -1
212334123434
$ echo $str4 | grep -oP "\d+" | sort -n | tail -1
212334123434
Run Code Online (Sandbox Code Playgroud)
这种方法的工作原理是选择所有数字序列的子串。然后我们按数字对这个输出进行排序sort -n
,然后使用 获取列表中的最后一个值tail -1
。这将是最长的子串。
您可以通过tail -1
关闭并重新运行以下示例之一来了解它是如何工作的:
$ echo $str4 | grep -oP "\d+" | sort -n
91234
212334123434
Run Code Online (Sandbox Code Playgroud)
上述方法适用于我能想到的每一种情况,除了一种情况。@terdon 在聊天中提到了这种情况,它挫败了上述方法。
所以要解决这个问题,你需要稍微改变策略。仍然可以利用上述方法的内核,但是我们也需要将字符数注入到结果中。这使 sort 能够按字符串中的字符数及其值对结果进行排序。
$ for i in $(echo $str0 | grep -oP "\d+");do a=$(echo "$i" | wc -c); \
echo "$a $i"; done | sort -n | tail -1 | cut -d" " -f2
Run Code Online (Sandbox Code Playgroud)
结果:
$ echo $str0
0000000000001a2test
$ for i in $(echo $str0 | grep -oP "\d+");do a=$(echo "$i" | wc -c); \
echo "$a $i"; done | sort -n | tail -1 | cut -d" " -f2
0000000000001
Run Code Online (Sandbox Code Playgroud)
您可以通过利用 Bash 使用${#var}
.
$ for i in $(echo $str0 | grep -oP "\d+");do echo "${#i} $i"; done | \
sort -n | tail -1 | cut -d" " -f2
0000000000001
Run Code Online (Sandbox Code Playgroud)
我选择使用grep -P ...
上面的,因为我,作为一个 Perl 开发人员,喜欢这样说所有数字的类语法:\d+
, 而不是[[:digit:]]\+
or [0-9]\+
。但是对于这个特定的问题,它并不是真正需要的。你可以grep
像这样轻松地换掉我用过的:
$ .... grep -o "[0-9]\+" ....
Run Code Online (Sandbox Code Playgroud)
例如:
$ for i in $(echo $str0 | grep -o "[0-9]\+");do echo "${#i} $i"; done | \
sort -n | tail -1 | cut -d" " -f2
0000000000001
Run Code Online (Sandbox Code Playgroud)
解决方案perl
:
echo 212334123434test233abc44 |
perl -nle 'print ((
map { $_->[0] }
sort{ $a->[1] <=> $b->[1] }
map { [$_,length] }
split /\D+/, $_)[-1]
)'
212334123434
Run Code Online (Sandbox Code Playgroud)
echo 212334123434test233abc44 |
awk '{gsub("[^0-9]+","\n"); print;}' |
awk '{ if (length($0) > max) {max = length($0); maxline = $0} }
END { print maxline }'
212334123434
Run Code Online (Sandbox Code Playgroud)
将 python 与命令行上传递的字符串一起使用,并假设您想要最大长度的第一个序列:
import sys
longest = current = ""
for x in sys.argv[1]:
if current and not x.isdigit():
if len(current) > len(longest):
longest = current
current = ""
else:
current += x
print(longest)
Run Code Online (Sandbox Code Playgroud)
这是另一种可以处理小数和整数的 Perl 方法:
echo "0.212334123434test233" |
perl -lne 'while(/([\d.]+)/g){$max=$1 if length($1) > length($max)} print $max'
Run Code Online (Sandbox Code Playgroud)
请注意,到目前为止发布的所有答案都不会涉及小数,并且由于您指定要最长的而不是数字最大的数字,因此我假设您实际上需要小数。
perl -lne
:-n
意思是“逐行读取输入,然后运行上面给出的脚本-e
”。在-l
每增加一个新行print
调用(和其他的东西在这里不相关)。while(/([\d.]+)/g)
: 遍历所有数字 (\d
意味着[0-9]
,所以[\d.]
将匹配数字和.
。如果您还想查找负数,请添加-
。括号捕获匹配的字符串,作为$1
下一步使用的字符串。$max=$1 if length($1) > length($max)
: 如果当前匹配的长度大于迄今为止最长的 ( $max
) 将匹配保存为$max
.print $max
: 打印找到的最长的数字串。这将在 while 循环完成后执行,因此在找到所有数字之后。给定的
str="212334123434test233"
Run Code Online (Sandbox Code Playgroud)
然后在 bash
max=""
while read num; do
(( ${#num} > ${#max} )) && max=$num
done < <(grep -Eo '[0-9]+' <<< "$str")
echo $max
212334123434
Run Code Online (Sandbox Code Playgroud)
使用通过用空格替换字符串中的非数字字符来代替 grep 构造的数组的可能更纯的 bash 解决方案
max=""
declare -a nums="${str//[^[:digit:]]/ }"
for num in ${nums[@]}; do
(( ${#num} > ${#max} )) && max=$num
done
echo $max
Run Code Online (Sandbox Code Playgroud)