去年从字符串发生



我有这样的字符串:

ACB 01900 X1911D 1910 1955-2011 3424 2135 1934 foobar

我正在尝试获取一年的最后一次出现(从 1900 年到 2050 年),所以我只需要从该字符串中提取1934年。

我正在尝试:

grep -P -o 's(19|20)[0-9]{2}s(?!s(19|20)[0-9]{2}s)'

grep -P -o '((19|20)[0-9]{2})(?!s1s)'

但它匹配:1910 年和 1934

年下面是正则表达式 101 示例:

https://regex101.com/r/UetMl0/3

https://regex101.com/r/UetMl0/4

另外:如何在不做额外的 grep 过滤它们的情况下提取没有周围空间的年份?

你有没有听过这句话:

Some people, when confronted with a problem, think
“I know, I'll use regular expressions.”   Now they have two problems. 

保持简单 - 你有兴趣找到 2 个数字之间的数字,所以只需使用数字比较,而不是正则表达式:

$ awk -v min=1900 -v max=2050 '{yr=""; for (i=1;i<=NF;i++) if ( ($i ~ /^[0-9]{4}$/) && ($i >= min) && ($i <= max) ) yr=$i; print yr}' file
1934

您没有说明如果范围内没有日期该怎么办,因此如果发生这种情况,上述内容会输出一个空行,但很容易调整以执行其他任何操作。

更改上面的脚本以查找第一个而不是最后一个日期是微不足道的(将打印移动到if内),在您的范围内使用不同的开始或结束日期是微不足道的(更改最小值和/或最大值)等等,等等,这强烈表明这是正确的方法。尝试使用基于正则表达式的解决方案更改任何这些要求。

我看不到使用grep执行此操作的方法,因为它不允许您只输出其中一个捕获组,只输出整个匹配项。

机智的perl我会做类似的事情

perl -lpe 'if (/^.*b(19dd|20(?:0-4d|50))b/) { print $1 }'

想法:使用^.*(贪婪)在前面消耗尽可能多的字符串,从而找到最后一个可能的匹配。在匹配的数字周围使用b(单词边界)以防止匹配01900X1911D。仅打印第一个捕获组 ($1)。

我试图实现你对1900-2050的要求;如果这太复杂,((?:19|20)dd)可以(但也匹配例如2099)。

使用 grep 完成任务的正则表达式可以如下所示:

b(?:19d{2}|20[0-4]d|2050)b(?!.*b(?:19d{2}|20[0-4]d|2050)b)

详:

  • b- 单词边界。
  • (?:- 非捕获组的开始,需要作为容器 选择。
    • 19d{2}|- 第一种选择(1900 - 1999)。
    • 20[0-4]d|- 第二种选择(2000 - 2049年)。
    • 2050- 第三种选择,只有 2050 年。
  • )- 非捕获组的结束。
  • b- 单词边界。
  • (?!- 负面展望:
    • .*- 任何字符的序列,实际上意味着"接下来的内容" 可以发生在更远的地方"。
    • b(?:19d{2}|20[0-4]d|2050)b- 与以前相同的表达式。
  • )- 负面展望的结束。

单词边界锚点提供您将不匹配数字 - 零件较长的单词,例如X1911D.

负预测提供您将仅匹配所需年份的最后一次出现。

如果可以使用grep以外的其他工具,则支持调用以前的 编号组(?n),其中n是另一个捕获的编号 组,正则表达式可以简单一点:

(b(?:19d{2}|20[0-4]d|2050)b)(?!.*(?1))

详:

  • (b(?:19d{2}|20[0-4]d|2050)b)- 像以前一样的正则表达式,但是 包含在捕获组中(稍后将"调用"它)。
  • (?!.*(?1))- 对捕获第 1 组的负面展望, 位于更远的任何地方。

这样,您可以避免再次编写相同的表达式。

有关regex101中的工作示例,请参阅 https://regex101.com/r/fvVnZl/1

您可以使用不带任何组的 PCRE 正则表达式,仅在以下情况下返回所需的模式的最后一次出现,前提是在模式前面加上^.*K,或者,在您的情况下,由于您希望有一个空格边界,^(?:.*s)?K

grep -Po '^(?:.*s)?K(?:19d{2}|20(?:[0-4]d|50))(?!S)' file

请参阅正则表达式演示。

  • ^- 行首
  • (?:.*s)?- 匹配 1 次或 0 次出现的可选非捕获组
    • .*- 除换行符字符以外的任何 0+ 字符,尽可能多
    • s- 空格字符
  • K- 匹配重置运算符丢弃到目前为止匹配的文本
  • (?:19d{2}|20(?:[0-4]d|50))-19和任何两位数字或20后跟从04的数字,然后是任何数字(0049)或50
  • (?!S)- 空格或字符串结尾。

观看在线演示:

s="ACB 01900 X1911D 1910 1955-2011 3424 2135 1934 foobar"
grep -Po '^(?:.*s)?K(?:19d{2}|20(?:[0-4]d|50))(?!S)' <<< "$s"
# => 1934

相关内容

  • 没有找到相关文章

最新更新