RegEx用于在year1之前匹配字符串

时间:2019-05-06 14:25:53

标签: regex string bash sed split

我有包含年号的目录名称。我想将它们拆分为年份数字之前的变量:

输入:

Holidays.uS.2019.bla.bla
Holidays.ca.old.2017.bla.bla
Holidays.2015.bla.bla.bla
Holidays.1.2.3.4.at.old.1999.bla.bla.bla.bla

年份并不总是在同一位置,但是,它总是有4位数字。

我一直都需要一年中的所有东西。

输入:

Holidays.ca.old.2017.bla.bla

输出:

Holidays.ca.old

尝试

set name Holidays.ca.old.2017.bla.bla
set numbers [regexp -all -inline {[0-9]+} $name]

我的代码输出的是年份数字,有时是其他错误的数字。

我在tcl中使用了它,对我来说效果很好:

set name_split [regsub {\.[0-9]{4}\y.*} $name ""]

bash脚本仍需要它,怎么使用?

这在bash中实际上不起作用:

name_split=$(echo $name | {\.[0-9]{4}\y.*}

5 个答案:

答案 0 :(得分:2)

您可以使用sed

name="Holidays.uS.2019.bla.bla"
name_split="$(sed 's/\.[0-9]\{4\}\>.*//' <<< $name)"
echo $name_split

输出:Holidays.uS,请参见online sed demo

注意:如果年份后必须有一个点,则可以匹配它而不是依靠单词边界:

name_split="$(sed 's/\.[0-9]\{4\}\..*//' <<< $name)"
                                 ^^ 

此处的sed命令表示:

  • s/-替代:
  • \.-一个点
  • [0-9]\{4\}-四位数
  • \>-尾随单词边界
  • .*-字符串的其余部分

带有空字符串。

答案 1 :(得分:1)

为了安全起见,您可以在sed命令中添加其他边界,并传递所需的字符:

代码

#!/bin/bash
STRING="Holidays.1.2.3.4.at.old.1999.bla.bla.bla.bla"
MATCH="$(sed 's/\([A-z0-9\.]*\)\(\.[0-9]\{4\}.*\)$/\1/' <<< $STRING)"
echo $MATCH

输出

Holidays.1.2.3.4.at.old

特殊字符

如果您不希望传递特殊字符,则this expression是安全的:

enter image description here

此图显示了它的工作原理

enter image description here

性能

此摘要显示了表达式的性能,重复了100万次。

repeat = 1000000;
start = Date.now();

for (var i = repeat; i >= 0; i--) {
	var string = "Holidays.1.2.3.4.at.old.1999.bla.bla.bla.bla";
	var regex = /^([A-z0-9\.]*)(\.[0-9]{4}.*)/g;
	var match = string.replace(regex, "$1");
}

end = Date.now() - start;
console.log("YAAAY! \"" + match + "\" is a match  ");
console.log(end / 1000 + " is the runtime of " + repeat + " times benchmark test.  ");

答案 2 :(得分:0)

以下是使用sed的选项:

echo "Holidays.ca.old.2017.bla.bla" | sed 's/^\(.*\)\.[0-9]\{4\}.*$/\1/';

Holidays.ca.old

正则表达式简单地捕获所有内容,直到最后一个点,然后是四位数的年份,然后仅替换为所捕获的数量:

(.*)        match and capture everything up until
\.[0-9]{4}  a literal dot, followed by a four digit year
.*          consume the remainder of the input

答案 3 :(得分:0)

这是不使用sed的另一种方式:

#!/bin/bash
test_str="Holidays.ca.old.2017.bla.bla"
reg_ex='^(.*)\.([0-9]{4})' # Easy to read reg_ex vs sed reg_ex gibberish
if [[ $test_str =~ $reg_ex ]]
then
  echo "1: ${BASH_REMATCH[1]}"
  echo "2: ${BASH_REMATCH[2]}"
fi

输出:

1:Holidays.ca.old

2:2017年

答案 4 :(得分:0)

您可以使用parameter expansion来做到这一点:

$ str='Holidays.1.2.3.4.at.old.1999.bla.bla.bla.bla'
$ echo "${str%.[[:digit:]][[:digit:]][[:digit:]][[:digit:]]*}"
Holidays.1.2.3.4.at.old

这将删除一个句点,后跟四位数字,然后是字符串末尾的任何内容(*通配符)。