두 문자열 사이에 지정된 문자를 바꾸시겠습니까?

두 문자열 사이에 지정된 문자를 바꾸시겠습니까?

마무리할 일이 있어요. & 내부 또는 사이의 모든 항목을 #으로 바꿔야 합니다 <ex> </ex>. 실제적인 예는 다음과 같습니다:

a & b & c <ex> a & b & c </ex> a & b & c

<ex>다시 말하지만, & 내부 와 이전 의 모든 항목을 바꿔야 합니다.</ex>

예상 출력:

a & b & c <ex> a # b # c </ex> a & b & c

이 작업을 수행하는 방법에 대한 설명을 게시하십시오.

편집 #1

sedAS400 시스템에서 실행할 예정이므로 Perl이나 기타 인터프리터를 설치할 수 없으므로 솔루션을 제공해주세요 .

답변1

<ex>...</ex>각 줄이 한 번만 나타나는 경우:

sed -e :1 -e 's@\(<ex>.*\)&\(.*</ex>\)@\1#\2@;t1'

여러 항목이 있을 수 있고 중첩되지 않은 경우(또는 중첩되어 &가장 깊은 항목만 바꾸려는 경우):

sed '
  s|_|_u|g        # replace all underscores with "_u"
  s|(|_o|g        # replace all open parentheses with "_o"
  s|)|_c|g        # replace all close parentheses with "_c"
  s|<ex>|(|g      # replace all open ex tags with "("
  s|</ex>|)|g     # replace all close ex tags with ")"

  :1              # a label

  s/\(([^()]*\)&\([^()]*)\)/\1#\2/g
                  # find:
                  #   an open parentheses, 
                  #   some non-parentheses chars (captured),
                  #   an ampersand, 
                  #   some non-parentheses chars (captured) and 
                  #   a close parentheses, 
                  # replace with
                  #   the first captured text, 
                  #   an octothorpe
                  #   the second captured text, 
                  # globally in the current record.

  t1              # if there was a successful replacement, goto label "1",
                  # else carry on

  s|(|<ex>|g      # restore open tags
  s|)|</ex>|g     # restore close tags
  s|_o|(|g        # restore open parentheses
  s|_c|)|g        # restore close parentheses
  s|_u|_|g        # restore underscores
'

중첩될 수 있고 이를 둘러싸는 것으로 바꾸려는 경우:

sed '
  s|_|_u|g;s|(|_o|g;s|)|_c|g
  s|<ex>|(|g;s|</ex>|)|g;:1
  s/\(([^()]*\)(\([^()]*\))\([^()]*)\)/\1_O\2_C\3/g;t1
  :2
  s/\(([^()]*\)&\([^()]*)\)/\1#\2/g;t2
  s|(|<ex>|g;s|)|</ex>|g
  s|_O|<ex>|g;s|_C|</ex>|g
  s|_o|(|g;s|_c|)|g;s|_u|_|g'

답변2

Perl(버전 5.14 필요)을 사용하여 다음을 수행하세요.

perl -pe 's%(<ex>.*?</ex>)% $1 =~ s/&/#/gr %eg'

이전 버전에서는 더 장황해야 했습니다.

perl -pe 's%(<ex>.*?</ex>)% ($_x = $1) =~ s/&/#/g; $_x %eg'

지침: <ex>태그 사이의 모든 내용을 에 넣고 $1& $1를 #으로 바꾸십시오.

답변3

또 다른 펄 명령,

$ perl -pe 's/&(?=(?:(?!<ex>|<\/ex>).)*<\/ex>)/#/g' file
a & b & c <ex> a # b # c </ex> a & b & c

위의 명령을 설명하기 전에, Negative Lookahead와 Positive Lookahead가 실제로 무엇을 하는지 설명하겠습니다.

정규식에서는 (?=...)긍정적인 예측을 의미합니다. 둘러보기(예: 긍정적 및 부정적 미리보기, 긍정적 및 부정적 미리보기)는 너비가 0인 일치 항목을 만듭니다. 즉, 어떤 문자와도 일치하지 않습니다. 일반적으로 긍정적 및 부정적 예측은 상태 확인 목적으로 사용됩니다. (?:...)비캡처 그룹 이라고도 합니다. 즉, 비캡처 그룹 내의 패턴만 일치됩니다. 어떤 문자도 캡처하지 않습니다.

  • (?!<ex>|<\/ex>)문자열 <ex>또는 .와 일치할 수 없습니다 </ex>.
  • (?:(?!<ex>|<\/ex>).)실제로 의미하는 바는 먼저 다음 3~4개의 문자를 찾고 다음 3~4개의 문자가 <ex>또는 이 될 수 없는지 확인한다는 것입니다 </ex>. .이 조건이 충족되면 다음 문자만 일치됩니다.
  • (?:(?!<ex>|<\/ex>).)*문자열 <ex>또는 가 감지될 때까지 위의 단계를 0번 이상 수행합니다. </ex>이 두 문자열 중 하나를 찾으면 갑자기 다음 문자 일치가 중단됩니다.

  • (?:(?!<ex>|<\/ex>).)*<\/ex>다음 </ex>문자열과도 일치합니다. 이것은 모두 예측에 반영됩니다.

  • &(?=(?:(?!<ex>|<\/ex>).)*<\/ex>)&마지막으로 위 조건을 만족하는 문자가 뒤에 오는 경우에만 문자와 일치합니다. 즉, &다음에는 속하지 않는 문자가 와야 하거나 닫는 표시가 0번 이상 와야 <ex>합니다 .</ex></ex>

답변4

중첩되지 않고 줄에서 두 번 이상 발생하면 도움이 될 수 있습니다.

#cat plop
>a & b & c <ex> a & b & c </ex> a & b & c <ex> a & b & c </ex> a & b & c

#cat plop |sed -e :1 -e 's@\(<ex>[^(</ex>)]*\)&\(.*</ex>\)@\1+\2@;t1'     
>a & b & c <ex> a + b + c </ex> a & b & c <ex> a + b + c </ex> a & b & c

관련 정보