正则表达式匹配单个字符实例

正则表达式匹配单个字符实例

我在工作中维护了这个东西,它使用了一个相当神秘的 DSL。而且它的工具不是很好。为了解决糟糕的工具问题,我编写了一些脚本,试图在将代码发送到生产环境之前找到代码的一些问题。

我当前试图解决的问题与变量名有关。变量的命名类似于@@Variable@@.如果只有 1 秒@或超过 2@秒,则为致命错误。

现在我已经让它循环遍历有问题的文件,并@@@在发现 3 个或更多连续的 时进行 grep 并引发错误@。所以那部分很酷。

但我有点卡在单身了@。一行上可以有多个变量。

@@Var1@@ words words words @@Var2@@  #This works
@Var1@@ words words words @@Var2@@   #This will fail because Var1 is wrong.
@@Var1@ words words words @@Var2@@   #This will fail because Var1 is wrong.
@@Var1@@ words words words @Var2@@   #This will fail because Var2 is wrong.
@@Var1@@ words words words @@Var2@   #This will fail because Var2 is wrong.

上面有很多排列,并且一行上的变量数量没有限制。

如果任何给定行上只有一个变量,则此 awk 脚本可以工作,但如果一行上有多个变量,则该 awk 脚本将不起作用。

awk '/@/ && ! /@@.*@@/' test.txt

我真正需要做的是匹配只有一个@.在上面的示例代码中,它将匹配除第 1 行之外的所有行。

答案1

$ sed 'h;s/@@[^@ ]*@@//g;/@/!d;g' file
@Var1@@ words words words @@Var2@@   #This will fail because Var1 is wrong.
@@Var1@ words words words @@Var2@@   #This will fail because Var1 is wrong.
@@Var1@@ words words words @Var2@@   #This will fail because Var2 is wrong.
@@Var1@@ words words words @@Var2@   #This will fail because Var2 is wrong.

sed命令删除有效的变量占位符并报告仍包含字符的行@。它还会查找包含@两侧都有两个以上占位符的行。

我们可以通过将每行保存到保留空间来报告原始的故障行h。然后运行删除潜在有效占位符的替换,如果之后不包含任何@字符,我们将删除该行。我们从保留空间中获取原始行,g如果存在则打印它。

如果您的变量遵循与大多数编程语言相同的命名规则,则可以将有效占位符 的模式@@[^@ ]*@@更改为。@@[[:alpha:]_][[:alnum:]_]*@@

假设您需要能够@在文本本身中包含字符。在这种情况下,您需要@在上面命令中的替换之前删除所有可能出现的不是变量占位符的有效星座。


一种更系统的方法是提取包含占位符的行,@其中一侧或另一侧有太多字符,删除正确的占位符,然后拉出占位符@在变量名称的两侧仅包含一个字符的行。

sed -e '/@\{3,\}[^@ ]*@\{1,\}/b' \
    -e '/@\{1,\}[^@ ]*@\{3,\}/b' \
    -e h \
    -e 's/@@[^@ ]*@@//g' \
    -e '/@[^@ ]*@/!d' \
    -e g file

上面的内容将允许您的文本在其他地方包含@字符,前提是它们不会以看起来像占位符的模式出现。

答案2

$ grep -E '(^|[^@])@([^@]|$)|@@@' file
@Var1@@ words words words @@Var2@@   #This will fail because Var1 is wrong.
@@Var1@ words words words @@Var2@@   #This will fail because Var1 is wrong.
@@Var1@@ words words words @Var2@@   #This will fail because Var2 is wrong.
@@Var1@@ words words words @@Var2@   #This will fail because Var2 is wrong.

或者:

$ awk '/(^|[^@])@([^@]|$)|@@@/' file
@Var1@@ words words words @@Var2@@   #This will fail because Var1 is wrong.
@@Var1@ words words words @@Var2@@   #This will fail because Var1 is wrong.
@@Var1@@ words words words @Var2@@   #This will fail because Var2 is wrong.
@@Var1@@ words words words @@Var2@   #This will fail because Var2 is wrong.

或一次分析一个字段:

$ cat tst.awk
{
    for (i=1; i<=NF; i++) {
        if ( $i ~ /^@[^@]|[^@]@$|@@@/ ) {
            print "Failed line:", NR, $0
            print "\tbecause of field", i, $i
        }
    }
}

$ awk -f tst.awk file
Failed line: 2 @Var1@@ words words words @@Var2@@   #This will fail because Var1 is wrong.
        because of field 1 @Var1@@
Failed line: 3 @@Var1@ words words words @@Var2@@   #This will fail because Var1 is wrong.
        because of field 1 @@Var1@
Failed line: 4 @@Var1@@ words words words @Var2@@   #This will fail because Var2 is wrong.
        because of field 5 @Var2@@
Failed line: 5 @@Var1@@ words words words @@Var2@   #This will fail because Var2 is wrong.
        because of field 5 @@Var2@

您不需要任何额外的东西来查找@@@案例,上面也包括查找该案例。

答案3

另一种解决方案是grep -E.正则表达式也适用于 awk

grep -E '[^@]@[^@]|^@[^@]|@[^@]$' tmpfile
@Var1@@ words words words @@Var2@@   #This will fail because Var1 is wrong.
@@Var1@ words words words @@Var2@@   #This will fail because Var1 is wrong.
@@Var1@@ words words words @Var2@@   #This will fail because Var2 is wrong.
@@Var1@@ words words words @@Var2@   #This will fail because Var2 is wrong.

awk '/[^@]@[^@]|^@[^@]|@[^@]$/' tmpfile
@Var1@@ words words words @@Var2@@   #This will fail because Var1 is wrong.
@@Var1@ words words words @@Var2@@   #This will fail because Var1 is wrong.
@@Var1@@ words words words @Var2@@   #This will fail because Var2 is wrong.
@@Var1@@ words words words @@Var2@   #This will fail because Var2 is wrong.

答案4

在支持的情况下,您可以使用负环视运算符grep -P来匹配单个s 或不被 s 包围的@3 个或更多 s 的序列:@@

<test.txt grep --color -P '(?<!@)(@|@{3,})(?!@)'

然而,这仍然会标记@@@@in@@var1@@@@var2@@并且无法标记不匹配的@@s,如 in@@var1@@var1@@var2@@

另一种方法是:

<test.txt grep --color -P '@@\w+@@(*SKIP)(*FAIL)|@+'

这将标记@不属于@@word@@序列的部分。

$ <test.txt grep --color -P '@@\w+@@(*SKIP)(*FAIL)|@+' @Var1@@ Words Words @@Var2@@ #这会失败,因为 Var1 是错误的。 @@Var1@wordswords@@Var2@@ #这会失败,因为 Var1 是错误的。 @@Var1@@wordswords@Var2@@#这将失败,因为 Var2 是错误的。 @@Var1@@wordswords@@Var2@#这将失败,因为Var2是错误的。

相关内容