去年发生的字符串

时间:2018-12-02 16:50:56

标签: regex grep match last-occurrence

我有这样的字符串:

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})(?!\s\1\s)'

但匹配:1910年和1934年

这是Regex101示例:

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

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

另外:如何在没有周围空间的情况下提取年份而不进行额外的grep筛选?

4 个答案:

答案 0 :(得分:1)

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

我会做些类似的事情

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

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

我试图执行您的1900-2050年要求;如果太复杂了,((?:19|20)\d\d)可以做到(但也可以匹配2099)。

答案 1 :(得分:1)

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

<nav id="mySidenav" class="sidenav">
<a href="javascript:void(0)" class="closebtn" onclick="closeNav();return false;">&times;</a>

    <img class="sidenavbar-logo-img" src='<?php echo get_template_directory_uri(); ?>/img/logo-NO.png'>

    <?php wp_nav_menu( array( 'theme_location' => 'sidenav-menu' ) ); ?>

<div class='sidebar-nav-info'>
    <p>Lower Trinity St,
    Birmingham,
    B9 4AG</p>
    <p>Facebook   Instagram</p>
    </div>

</nav>

  <!-- Use any element to open the sidenav -->
  <span class="hamburger" onclick="openNav(); return false;">
<i class="fas fa-bars"></i>
</span>

详细信息:

  • /* The navigation menu links */ .sidenav ul { list-style-type: none; margin-left: 0; } .sidenav ul li { margin: 0; } .sidenav a { padding: 8px 8px 8px 0px; text-decoration: none; font-weight: 700; font-size: 18px; color: #f1f1f1; display: block; transition: 0.3s; } /* When you mouse over the navigation links, change their color */ .sidenav a:hover { color: #818181; text-decoration: none; } /* Position and style the close button (top right corner) */ .sidenav .closebtn { position: absolute; top: 0; right: 25px; font-size: 36px; margin-left: 50px; } /* Style page content - use this if you want to push the page content to the right when you open the side navigation */ #main { transition: margin-left .5s; padding: 20px; } /* On smaller screens, where height is less than 450px, change the style of the sidenav (less padding and a smaller font size) */ @media screen and (max-height: 450px) { .sidenav {padding-top: 15px;} .sidenav a {font-size: 18px;} } .sidebar-nav-info { padding: 30px; position: absolute; bottom: 0; left: 0; width: 200px; color: #E2E2E2; font-size: 12px; } /** HAMBURGER ICON **/ span.hamburger { position: sticky; top: 30px; left: 30px; font-size: 30px; font-weight: 800; cursor: e-resize; } -单词边界。
  • <script> /* Set the width of the side navigation to 250px and the left margin of the page content to 250px */ function openNav() { document.getElementById("mySidenav").style.width = "300px"; document.getElementById("main").style.marginLeft = "300px"; } /* Set the width of the side navigation to 0 and the left margin of the page content to 0 */ function closeNav() { document.getElementById("mySidenav").style.width = "0"; document.getElementById("main").style.marginLeft = "0"; } </script> -一个非捕获组的开始,需要作为一个容器 备择方案。
    • \b(?:19\d{2}|20[0-4]\d|2050)\b(?!.*\b(?:19\d{2}|20[0-4]\d|2050)\b) -第一种选择(1900年-1999年)。
    • \b-第二种选择(2000年-2049年)。
    • (?:-第三种选择,仅2050年。
  • 19\d{2}|-非捕获组的结尾。
  • 20[0-4]\d|-单词边界。
  • 2050-负前瞻:
    • )-任何字符的序列,实际上意味着“后面是什么 可以在任何其他地方发生。”
    • \b-与以前相同的表达式。
  • (?!-否定前瞻的结尾。

边界锚词提供您不匹配数字-部分 的更长的单词,例如.*

否定前瞻表示您将仅匹配最后 所需年份的发生。

如果您可以使用 grep 以外的其他工具,则支持调用上一个 编号为\b(?:19\d{2}|20[0-4]\d|2050)\b的组,其中 n 是另一个捕获的编号 组,正则表达式可能会更简单:

)

详细信息:

  • X1911D-正则表达式与以前一样,但是 包含在捕获组中(稍后将被称为)。
  • (?n)-捕获组1的负向超前 位于更远的地方。

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

有关(\b(?:19\d{2}|20[0-4]\d|2050)\b)(?!.*(?1)) 中的有效示例,请参见https://regex101.com/r/fvVnZl/1

答案 2 :(得分:1)

如果在模式前面加上^.*\K,或者由于您希望有空白边界,{{ 1}}:

^(?:.*\s)?\K

请参见regex demo

详细信息

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

查看online demo

50

答案 3 :(得分:1)

您听说过this saying吗?

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中移动打印内容),使用范围内不同的开始或结束日期是微不足道的(更改最小值和/或最大值)等),这强烈表明这是正确的方法。尝试使用基于正则表达式的解决方案更改所有这些要求。