搜尋包含不匹配分隔符的行
執行
pdflatex
時崩潰,我的.aux
文件包含如下行\@writefile{toc}{\contentsline {section}{\numberline {B
我能想到的辨識此類行的唯一方法是計算 ’ 的數量是否
{
超過}
任何行中 ’ 的數量。我希望能夠檢查.aux
生成的文件pdflatex
並確定它是否包含這樣的行。有沒有辦法使用 或其他實用程序來做到這grep
一點awk
?當然,如果有另一種更有效的方法來辨識這些線條,我會很高興。感謝您的建議
這是另一個簡短的:
awk '{while(gsub(/{[^{}]*}/, "")){ }} /[{}]/ {exit 1}'
或者可能
awk '{x=$0;while(gsub(/{[^{}]*}/, "")){ }} /[{}]/ {print FILENAME,FNR,x;nextfile}'
這會刪除所有的平衡
{...}
,如果仍然有{
or}
字元,則採取一些行動。
是的,在 grep(使用 PCRE)中是可能的(並且非常精確),但並不容易理解。
grep -Px '((?>[^{}]+|\{(?1)\})*)'
或者,我們可以定義輸入 (
$str
) 和適當的正則表達式 ($re
):$ printf '%s\n' "$str" | grep -vP "${re//[ $'\n']/}"
那是如何工作的?
當今的正則表達式可以匹配平衡的結構(不是大多數舊的正則表達式引擎)。
在 PCRE 中,遞歸是做到這一點的關鍵。
為了匹配一個平衡的集合,需要這個結構:
b(m|(?R))*e
b
開始模式在哪裡({
在你的情況下),
e
結束模式在哪裡(在你的情況}
下),中間
m
模式在哪裡([^{}]+
在你的情況下)。{([^{}]*+|(?R))*}
正如在這裡所看到的那樣。
但這是一個遞歸整個正則表達式 ( ) 的非錨定匹配
?R
。可以使用grep 選項獲得錨定版本(以匹配整行)。
-x
允許大括號之外的其他文本的完整解決方案變得有點複雜,因此,使用 Perl 正則表達式的選項來忽略我們可以編寫的空格。並將正則表達式結構更改為(有點慢):
((m+|b(?1)e)*)
原來的結構
b(m|(?R))*e
。(?(DEFINE)(?'nonbrace' [^{}\n] )) # Define a non-brace (?(DEFINE)(?'begin' { )) # Define the start text (?(DEFINE)(?'end' } )) # define the end text (?(DEFINE)(?'middle' (?&nonbrace) )) # define the allowed text # inside the braces (?(DEFINE)(?'nested' # define a nested ((?&begin)((?&middle)|(?&nested))*(?&end)) # pattern )) # here ^((?&nonbrace)*+(?&nested))*+(?&nonbrace)*$ # finally, use this regex.
正如這裡測試的那樣。
或替代結構
((m+|b(?1)e)*)
(?(DEFINE)(?'nonbrace' [^{}\n] )) # Define a non-brace (?(DEFINE)(?'begin' \{ )) # Define the start text (?(DEFINE)(?'end' \} )) # define the end text (?(DEFINE)(?'middle' (?&nonbrace) )) # define the allowed text # inside the braces (?(DEFINE)(?'nested' # define a nested ( (?&middle)++ | (?&begin)(?&nested)(?&end) )* )) ^(?&nested)$ # finally, use this regex.
如此處測試
請注意,一旦帶有許多 DEFINE 的非常長的正則表達式被正則表達式引擎編譯,它的工作速度與較短的正則表達式相同。
增加的功能是描述對人類來說更清晰(或者,至少,我希望如此)。
這顯示了對正則表達式的更清晰的描述,通常更易於人類理解,但使用了 PCRE 中相當深入的正則表達式特徵。
腳本
要將所有這些想法與 grep(GNU 和 PCRE)一起使用,請使用以下 shell (bash) 範例:
#!/bin/bash str=$' a abc {} {a} {{aa}} {a{b}} {a{bb}a} {a{b{c}b}a} n{a{}}nn{b{bb}} \@writefile{toc}}}}{\\contentsline {section}{\\numberline {B \@writefile{toc}{\contentsline {section}{\\numberline {B Previous lines contain mismatched braces. This and the next line don\'t. \@writefile{toc}{\\contentsline {section}{\\numberline {B}}} ' re=$' (?(DEFINE)(?\'nonbrace\' [^{}\\n] )) (?(DEFINE)(?\'begin\' { )) (?(DEFINE)(?\'end\' } )) (?(DEFINE)(?\'middle\' (?&nonbrace) )) (?(DEFINE)(?\'nested\' ((?&begin)((?&middle)|(?&nested))*(?&end)) )) ^((?&nonbrace)*(?&nested))*(?&nonbrace)*$ ' printf '%s\n' "$str" | grep -P "${re//[ $'\n']/}" a abc {} {a} {{aa}} {a{b}} {a{bb}a} {a{b{c}b}a} n{a{}}nn{b{bb}} Previous lines contain mismatched braces. This and the next line don't. \@writefile{toc}{\contentsline {section}{\numberline {B}}}
試驗結果
最後,要讓所有不匹配的行反轉輸出
-v
(如果您需要在執行的 shell 中執行以下內容,請參考上面的腳本):$ printf '%s\n' "$str" | grep -vP "${re//[ $'\n']/}" \@writefile{toc}}}}{\contentsline {section}{\numberline {B \@writefile{toc}{ntentsline {section}{\numberline {B