일치하지 않는 구분 기호가 포함된 줄 검색

일치하지 않는 구분 기호가 포함된 줄 검색

실행할 때 충돌이 발생 pdflatex하고 내 .aux파일에 다음과 같은 줄이 포함되어 있습니다.

\@writefile{toc}{\contentsline {section}{\numberline {B

그러한 행을 식별하기 위해 제가 생각할 수 있는 유일한 방법은 숫자가 행의 숫자를 초과하는지 계산하는 것입니다 {. 생성된 파일을 검사 하고 해당 줄이 포함되어 있는지 확인 }하고 싶습니다 . 또는 다른 유틸리티를 사용하여 이를 수행할 수 있는 방법이 있습니까 ? 물론 이러한 선을 식별하는 보다 효율적인 대안이 있다면 기쁠 것입니다..auxpdflatexgrepawk

어떤 제안이라도 보내주셔서 감사합니다

답변1

또 다른 짧은 내용은 다음과 같습니다.

awk '{while(gsub(/{[^{}]*}/, "")){ }} /[{}]/ {exit 1}'

아니면 어쩌면

awk '{x=$0;while(gsub(/{[^{}]*}/, "")){ }} /[{}]/ {print FILENAME,FNR,x;nextfile}'

그러면 균형 잡힌 모든 항목이 제거되고 또는 문자가 여전히 존재하는 {...}경우 일부 조치가 취해집니다 .{}

답변2

예, 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)에서 이러한 모든 아이디어를 사용하려면 다음 쉘(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(실행 중인 셸에서 다음을 실행해야 하는 경우 위의 스크립트를 가져옵니다).

$ printf '%s\n' "$str" | grep -vP "${re//[ $'\n']/}"

\@writefile{toc}}}}{\contentsline {section}{\numberline {B
\@writefile{toc}{ntentsline {section}{\numberline {B

답변3

sed@rowboat 메소드 번역 awk:

sed 'h; s/[^{}]//g; :1
     s/{}//g; t1
     /./!d; g'

그건:

sed '
  h; # save a copy of the line on the hold space
  s/[^{}]//g; # remove all characters but { and }
  :1
    s/{}//g; # remove the {}s (so starting with inner ones)
  # and loop until there's no more {} to remove
  t1

  /./!d; # if the pattern space does not contain any single
         # character, that means all {} were matched. Delete

  g; # otherwise retrieve the saved copy which will be printed
     # at the end of the cycle'

이는 POSIX이지만 awk다음과 같은 Perl과 같은 재귀 정규식을 사용하는 솔루션보다 훨씬 느립니다.

grep -Pvx '((?:[^{}]++|\{(?1)\})*+)'

답변4

사용 awk:

  • 각 레코드에 대해 합계는 0으로 초기화됩니다.
  • 한 줄씩 한 줄씩 검사를 시작하세요.
  • 여는 중괄호를 처음 볼 때 합계를 늘리고, 닫는 중괄호를 볼 때 합계를 줄입니다.
  • 합계가 0 아래로 떨어지면 중지하세요.
  • for 루프의 끝에 도달하면 음수 합계로 인해 중간에 있거나 일반적으로 합계가 0이 아닌 경우 0이 아닌 상태로 종료됩니다.
  • 참고: 이 방법은 중괄호 수를 계산하는 것과 다릅니다. 여기서는 합계가 음수가 되면 처리를 중지합니다.
awk 'BEGIN { a["{"]=1;a["}"]=-1 }
{ for (s=i=0; i++<length();) if (0>(s += a[substr($0,i,1)])) break }
s {exit 1}' file

같은 것perl

perl -lne '
  local(%h,$^R) = qw/{ 1 } -1/;
  /(?:(?:([{}])(?{$^R+=$h{$1}})|[^{}]+)(?(?{$^R<0})(?!)))+/g;
  exit 1 if $^R;
' file

Perl은 자체 미니 프로그래밍 언어와 거의 유사한 강력한 정규식 기능을 갖추고 있습니다. 정규식 내에서 루프를 실행하고 합계를 업데이트하며 합계가 0 아래로 떨어지는 시점을 모니터링합니다.

관련 정보