텍스트 파일에서 대괄호를 찾는 방법은 무엇입니까?


32

오늘 저는 필자가 perl -c filename반드시 Perl 스크립트가 아닌 임의의 파일에서 일치하지 않는 중괄호 {}를 찾는 데 사용할 수 있다는 것을 배웠습니다 . 문제는 다른 유형의 대괄호 () [] 및 아마도 <>에서 작동하지 않는다는 것입니다. 필자는 필적 할 수없는 대괄호를 찾는 데 도움이되었지만 지금까지는 좋지 않은 Vim 플러그인을 실험했습니다.

대괄호가 많은 텍스트 파일이 있는데 그 중 하나가 없습니다! 필적 할 수없는 대괄호를 식별하는 데 도움이되는 프로그램 / 스크립트 / vim 플러그인 / 무엇이 있습니까?

답변:


22

빔에서는 사용할 수 있습니다 []다음 키 입력에 입력 된 유형의 가장 가까운 타의 추종을 불허하는 브래킷에 신속하게 여행한다.

따라서 [{가장 근접한 "{"로 다시 이동합니다. ])가장 근접한 ")"등으로 이동합니다.


좋아, 이것은 나에게 완벽하다. 이 답변을 수락하려고하는데 이것을 분석 할 수있는 텍스트 처리 도구가 있는지 기다리는 중입니다.
phunehehe

6
또한 vim에서 % (미국에서는 Shift 5)를 사용하여 현재 사용중인 브래킷 과 일치하는 브래킷 을 즉시 찾을 수 있다고 덧붙입니다.
atroon

@Atroon Ooo, 좋습니다. 저 자신을 아직 몰랐습니다. 나는 때때로 스택 교환을 좋아합니다. :)
Shadur

는 <KBD> [</ KBD>와 <KBD>] </ KBD> 정말 점프
wirrbel

나는 R에서 누락 된}을 찾으려고 4000 라인을 통과하는 거의 하루를 보냈습니다. 이것이 답이었습니다. 다시 한번, VIM 감사합니다! 그러나 이것이 소스 코드 파일을 작은 덩어리로 나누는 데 좋은 주장이라고 생각합니다.
Thomas Browne

7

업데이트 2 :
다음 스크립트는 이제 mismached의 행 번호와 열 출력한다 브래킷 . 스캔 당 하나의 대괄호 유형을 처리합니다 (예 : '[]' '<>' '{}' '()'...)
스크립트는 첫 번째 , 일치하지 않는 오른쪽 대괄호 또는 짝이없는 왼쪽 대괄호 중 첫 번째를 식별합니다. ... 오류를 감지하면 줄 번호와 열 번호로 종료됩니다.

샘플 출력은 다음과 같습니다.


File = /tmp/fred/test/test.in
Pair = ()

*INFO:  Group 1 contains 1 matching pairs

ERROR: *END-OF-FILE* encountered after Bracket 7.
        A Left "(" is un-paired in Group 2.
        Group 2 has 1 un-paired Left "(".
        Group 2 begins at Bracket 3.
  see:  Line, Column (8, 10)
        ----+----1----+----2----+----3----+----4----+----5----+----6----+----7
000008  (   )    (         (         (     )   )                    

여기 스크립트가 있습니다 ...


#!/bin/bash

# Itentify the script
bname="$(basename "$0")"
# Make a work dir
wdir="/tmp/$USER/$bname"
[[ ! -d "$wdir" ]] && mkdir -p "$wdir"

# Arg1: The bracket pair 'string'
pair="$1"
# pair='[]' # test
# pair='<>' # test
# pair='{}' # test
# pair='()' # test

# Arg2: The input file to test
ifile="$2"
  # Build a test source file
  ifile="$wdir/$bname.in"
  cp /dev/null "$ifile"
  while IFS= read -r line ;do
    echo "$line" >> "$ifile"
  done <<EOF
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[   ]    [         [         [
<   >    <         
                   <         >         
                             <    >    >         >
----+----1----+----2----+----3----+----4----+----5----+----6
{   }    {         }         }         }         } 
(   )    (         (         (     )   )                    
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
EOF

echo "File = $ifile"
# Count how many: Left, Right, and Both
left=${pair:0:1}
rght=${pair:1:1}
echo "Pair = $left$rght"
# Make a stripped-down 'skeleton' of the source file - brackets only
skel="/tmp/$USER/$bname.skel" 
cp /dev/null "$skel"
# Make a String Of Brackets file ... (It is tricky manipulating bash strings with []..
sed 's/[^'${rght}${left}']//g' "$ifile" > "$skel"
< "$skel" tr  -d '\n'  > "$skel.str"
Left=($(<"$skel.str" tr -d "$left" |wc -m -l)); LeftCt=$((${Left[1]}-${Left[0]}))
Rght=($(<"$skel.str" tr -d "$rght" |wc -m -l)); RghtCt=$((${Rght[1]}-${Rght[0]}))
yBkts=($(sed -e "s/\(.\)/ \1 /g" "$skel.str"))
BothCt=$((LeftCt+RghtCt))
eleCtB=${#yBkts[@]}
echo

if (( eleCtB != BothCt )) ; then
  echo "ERROR:  array Item Count ($eleCtB)"
  echo "     should equal BothCt ($BothCt)"
  exit 1
else
  grpIx=0            # Keep track of Groups of nested pairs
  eleIxFir[$grpIx]=0 # Ix of First Bracket in a specific Group
  eleCtL=0           # Count of Left brackets in current Group 
  eleCtR=0           # Count of Right brackets in current Group
  errIx=-1           # Ix of an element in error.
  for (( eleIx=0; eleIx < eleCtB; eleIx++ )) ; do
    if [[ "${yBkts[eleIx]}" == "$left" ]] ; then
      # Left brackets are 'okay' until proven otherwise
      ((eleCtL++)) # increment Left bracket count
    else
      ((eleCtR++)) # increment Right bracket count
      # Right brackets are 'okay' until their count exceeds that of Left brackets
      if (( eleCtR > eleCtL )) ; then
        echo
        echo "ERROR:  MIS-matching Right \"$rght\" in Group $((grpIx+1)) (at Bracket $((eleIx+1)) overall)"
        errType=$rght    
        errIx=$eleIx    
        break
      elif (( eleCtL == eleCtR )) ; then
        echo "*INFO:  Group $((grpIx+1)) contains $eleCtL matching pairs"
        # Reset the element counts, and note the first element Ix for the next group
        eleCtL=0
        eleCtR=0
        ((grpIx++))
        eleIxFir[$grpIx]=$((eleIx+1))
      fi
    fi
  done
  #
  if (( eleCtL > eleCtR )) ; then
    # Left brackets are always potentially valid (until EOF)...
    # so, this 'error' is the last element in array
    echo
    echo "ERROR: *END-OF-FILE* encountered after Bracket $eleCtB."
    echo "        A Left \"$left\" is un-paired in Group $((grpIx+1))."
    errType=$left
    unpairedCt=$((eleCtL-eleCtR))
    errIx=$((${eleIxFir[grpIx]}+unpairedCt-1))
    echo "        Group $((grpIx+1)) has $unpairedCt un-paired Left \"$left\"."
    echo "        Group $((grpIx+1)) begins at Bracket $((eleIxFir[grpIx]+1))."
  fi

  # On error, get Line and Column numbers
  if (( errIx >= 0 )) ; then
    errLNum=0    # Source Line number (current).
    eleCtSoFar=0 # Count of bracket-elements in lines processed so far.
    errItemNum=$((errIx+1)) # error Ix + 1 (ie. "1 based")
    # Read the skeketon file to find the error line-number
    while IFS= read -r skline ; do
      ((errLNum++))
      brackets="${skline//[^"${rght}${left}"]/}" # remove whitespace
      ((eleCtSoFar+=${#brackets}))
      if (( eleCtSoFar >= errItemNum )) ; then
        # We now have the error line-number
        # ..now get the relevant Source Line 
        excerpt=$(< "$ifile" tail -n +$errLNum |head -n 1)
        # Homogenize the brackets (to be all "Left"), for easy counting
        mogX="${excerpt//$rght/$left}"; mogXCt=${#mogX} # How many 'Both' brackets on the error line? 
        if [[ "$errType" == "$left" ]] ; then
          # R-Trunc from the error element [inclusive]
          ((eleTruncCt=eleCtSoFar-errItemNum+1))
          for (( ele=0; ele<eleTruncCt; ele++ )) ; do
            mogX="${mogX%"$left"*}"   # R-Trunc (Lazy)
          done
          errCNum=$((${#mogX}+1))
        else
          # errType=$rght
          mogX="${mogX%"$left"*}"   # R-Trunc (Lazy)
          errCNum=$((${#mogX}+1))
        fi
        echo "  see:  Line, Column ($errLNum, $errCNum)"
        echo "        ----+----1----+----2----+----3----+----4----+----5----+----6----+----7"  
        printf "%06d  $excerpt\n\n" $errLNum
        break
      fi
    done < "$skel"
  else
    echo "*INFO:  OK. All brackets are paired."
  fi
fi
exit

이 스크립트는 훌륭합니다!
Jonathan Dumaine

1
이것은 굉장하지만, Line, Column (8, 10)어떤 파일을 사용해도 항상 인쇄하는 것처럼 보입니다 . 또한 mogXCt=${#mogX}설정되었지만 어디서나 사용되지는 않습니다.
Clayton Dukes 17

5

가장 좋은 옵션은 Shadur가 식별 한 vim / gvim이지만 스크립트를 원한다면 Stack Overflow 에서 비슷한 질문에 대한 내 대답 을 확인할 수 있습니다 . 나는 여기에 전체 대답을 반복합니다.

당신이하려는 일이 범용 언어에 적용된다면, 이것은 사소한 문제가 아닙니다.

시작하려면 주석과 문자열에 대해 걱정해야합니다. 정규식을 사용하는 프로그래밍 언어로 이것을 확인하려면 퀘스트를 다시 어렵게 만듭니다.

그래서 내가 들어 와서 당신의 질문에 대한 조언을하기 전에 당신의 문제 영역의 한계를 알아야합니다. 문자열, 주석 및 정규 표현식이 없다는 것을 보장 할 수 있다면-또는 코드에서 균형이 맞지 않는 용도 이외의 대괄호를 사용할 수있는 코드의 일반적인 부분은 없습니다. 인생을 훨씬 간단하게 만듭니다.

확인하려는 언어를 아는 것이 도움이 될 것입니다.


노이즈가 없다고 가정합니다. 즉, 모든 괄호가 유용한 괄호라면 내 전략은 반복적입니다.

내부 브래킷이없는 모든 내부 브래킷 쌍을 찾아서 제거합니다. 이것은 모든 줄을 하나의 긴 줄로 접는 것이 가장 좋습니다 (정보를 가져와야 할 경우 줄 참조를 추가하는 메커니즘을 찾으십시오). 이 경우 검색 및 바꾸기는 매우 간단합니다.

배열이 필요합니다 :

B["("]=")"; B["["]="]"; B["{"]="}"

그리고 그 요소들을 반복합니다 :

for (b in B) {gsub("[" b "][^][(){}]*[" B[b] "]", "", $0)}

내 테스트 파일은 다음과 같습니다.

#!/bin/awk

($1 == "PID") {
  fo (i=1; i<NF; i++)
  {
    F[$i] = i
  }
}

($1 + 0) > 0 {
  count("VIRT")
  count("RES")
  count("SHR")
  count("%MEM")
}

END {
  pintf "VIRT=\t%12d\nRES=\t%12d\nSHR=\t%12d\n%%MEM=\t%5.1f%%\n", C["VIRT"], C["RES"], C["SHR"], C["%MEM"]
}

function count(c[)
{
  f=F[c];

  if ($f ~ /m$/)
  {
    $f = ($f+0) * 1024
  }

  C[c]+=($f+0)
}

내 전체 스크립트 (라인 참조 없음)는 다음과 같습니다.

cat test-file-for-brackets.txt | \
  tr -d '\r\n' | \
  awk \
  '
    BEGIN {
      B["("]=")";
      B["["]="]";
      B["{"]="}"
    }
    {
      m=1;
      while(m>0)
      {
        m=0;
        for (b in B)
        {
          m+=gsub("[" b "][^][(){}]*[" B[b] "]", "", $0)
        }
      };
      print
    }
  '

해당 스크립트의 출력은 대괄호의 가장 안쪽 불법 사용으로 중지됩니다. 그러나주의하십시오 : 1 /이 스크립트는 주석, 정규 표현식 또는 문자열에서 괄호와 함께 작동하지 않습니다 .2 / 원본 파일에서 문제가있는 위치를보고하지 않습니다. 오류 조건 및 모든 괄호 괄호를 유지합니다.

Point 3 /은 아마도 악용 가능한 결과이지만, 내가보고 한보고 메커니즘을 잘 모르겠습니다.

Point 2 /는 구현하기가 상대적으로 쉽지만 생성하는 데 몇 분 이상 걸리므로 알아낼 수 있도록 맡겨 두겠습니다.

포인트 1 /은 까다로운 부분입니다. 때로는 중첩 된 시작과 끝 또는 특수 문자에 대한 특별 인용 규칙과 경쟁하는 완전히 새로운 영역을 입력하기 때문입니다 ...


1
고마워요, 당신은 저를 구했습니다. 30k 라인 json 파일에서 일치하지 않는 괄호가 하나 있습니다.
I82 많은
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.