열 시작 부분의 작은따옴표 바꾸기

열 시작 부분의 작은따옴표 바꾸기

일부 열에 선행 작은따옴표가 포함된 입력 파일을 제어할 수 없는 수준으로 받았습니다.

'foo|'012|that's nice|bar

예상되는 출력을 얻으려면 각 필드에서 모든 선행 작은따옴표를 제거하고 싶습니다.

foo|012|that's nice|bar

awk를 사용하여 gsub 정규식 메타 문자가 ^열별로 작동할 것이라고 가정했지만 줄 시작 부분에서만 작동하는 것 같습니다.

$ echo "'foo|'012|that's nice|bar" | awk -F'|' '{gsub(/^'\''/,"")}1'
foo|'012|that's nice|bar

각 열에서 선행 작은따옴표를 제거하는 방법은 무엇입니까?

답변1

아니요 awk, sed다음과 같이 할 수 있습니다.

sed -E "s/(^|\|)'/\1/g"

-E확장 정규식으로 전환하는 옵션은 POSIX 표준의 다음 버전에 나타날 예정이지만 대부분의 구현에서는 이미 이를 지원합니다 sed. 또는 and perl대신 which를 사용할 수 있습니다 .sedawk

perl -pe 's/(^|\|)'\''/$1/g'

또는:

perl -pe "s/(^|\|)\K'//g"

( 경기 시작을 \K표시합니다 ).K

또는:

perl -pe "s/(?<![^|])'//g"

( '앞에 문자가 없으면 대체 가능합니다 |.)

또는 해당 awk패턴을 사용하십시오.

perl -F'\|' -pe 's/^'\''// for @F; $_ = join "|", @F'

를 사용하려면 awk -F'|'위의 perl패턴 과 같이 각 필드에 대체를 적용해야 합니다 awk.

awk -F'|' -v OFS='|' '
  {
    for (i = 1; i <= NF; i++) sub(/^'\''/, "", $ i)
    print
  }'

awk경우 특수한 경우로 필드 구분 기호가 단일 문자인 경우 정규 표현식으로 처리되지 않으므로 이스케이프할 필요가 없습니다 |.

$in은 awk숫자를 취하는 단항 연산자입니다. 1과 사이의 숫자이면 해당 필드를 반환합니다 NF. 숫자가 0이면 전체 레코드를 반환하고, 그렇지 않으면 빈 문자열을 반환합니다.

sub()그리고 gsub()2개 또는 3개의 인수를 취할 수 있으며, 세 번째 인수((유일한) 대체 주제)가 제공되지 않으면 기본값은 전체 레코드( $0)입니다. 다른 방법과 마찬가지로 다른 방법도 마찬가지입니다 gsub(). 패턴의 모든 발생이 아니라 첫 번째 패턴 발생만 대체됩니다.sub()s/x/y/gs/x/y/sedsub()gsub()

여기 정규식은 처음에 고정되어 있으므로 한 번만 일치할 수 있으므로 및 는 sub()아무런 gsub()효과가 없습니다.

IOW는 gsub()각 필드에서 하나의 교체를 수행하는 대신 다음을 수행합니다.하나기본적으로 분할되지 않은 전체 레코드인 문자열입니다.


¹ 기술적으로는 다음과 같이 간주됩니다.숫자 문자열. 즉, 숫자처럼 보이면 그렇지 않으면 숫자로 처리됩니다. 빈 문자열은 문자열로 처리됩니다.

답변2

필드를 반복하고 각 필드의 따옴표 문자를 바꿔야 합니다. Stéphane이 사용 방법을 보여줍니다.awk 그들의 대답에.

$ mlr --csv --fs pipe -N put 'for (k,v in $*) { $[k] = sub(v, "^\047", "") }' file
foo|012|that's nice|bar

이는 다음을 사용합니다.밀러( mlr)입력을 헤더 없는 CSV 데이터 세트로 읽습니다(파이프를 필드 구분 기호로 사용). 각 레코드에 대해 put표현식은 모든 필드를 반복하고 작은따옴표(8진수에서는 047)인 경우 첫 번째 문자를 제거합니다.


Miller의 다른 접근 방식은 apply()필드에서 초기 작은따옴표를 제거하는 함수를 적용하는 것입니다. 이 기능은 모든 레코드의 모든 필드에 적용됩니다.

$ mlr --csv --fs pipe -N put '$* = apply($*, func(k,v) { return { k: sub(v, "^\047", "") } })' file
foo|012|that's nice|bar

답변3

GNU awk 사용 gensub()(다른 awk도 지원하지만 아직 POSIX에서는 필요하지 않음):

$ awk '{$0=gensub(/(^|\|)\047/,"\\1","g")} 1' file
foo|012|that's nice|bar

위에서 할 수 있어 print gensub(...)좀 더 효율적이지만 할당 $0하고 인쇄하고 있습니다.1아래의 다른 답변과 일관성을 유지하고 교체 후 실제로 필드에서 작업을 수행해야 하는 경우를 대비합니다.

또는 GNU awk를 사용하세요 RT.

$ awk -v RS='|' '{ORS=RT; sub(/^\047/,"")} 1' file
foo|012|that's nice|bar

또는 awk를 사용하십시오.

$ awk '{gsub(/\|\047/,"|"); sub(/^\047/,"")} 1' file
foo|012|that's nice|bar

또는 awk를 사용하십시오.

$ awk -F "[|]'" -v OFS='|' '{$1=$1; sub(/^\047/,"")} 1' file
foo|012|that's nice|bar

바라보다http://awk.freeshell.org/PrintASingleQuote나는 왜 를 대표하는 \047데 익숙합니까 '?

알로크문자열 조작 함수( *sub(), match(), *split(), index(), 등) substr()length()매개변수로 제공하는 모든 문자열에서 작동합니다. 문자열 매개변수가 필요하지 않은 문자열의 경우 기본값은 $0매개변수로 제공되는 문자열이 없다는 것입니다. 문자열을 작업하기 전에 필드 등으로 분할하지 않으므로 어떤 이유로 한 번에 하나의 필드를 변경하려면 sub()한 번에 각 필드를 호출하는 루프를 작성해야 합니다.

$ awk 'BEGIN{FS=OFS="|"} {for (i=1; i<=NF; i++) sub(/^\047/,"",$i)} 1' file
foo|012|that's nice|bar

그러나 이는 다음 중 하나를 사용하는 것보다 효율성이 떨어집니다.

awk '{$0=gensub(/(^|\|)\047/,"\\1","g")} 1' file
awk '{gsub(/\|\047/,"|"); sub(/^\047/,"")} 1' file

부터:

  1. *sub()NF를 1~2번이 아니라 행당 여러 번 호출합니다 .
  2. 이는 awk가 필드 분할을 수행하도록 하는 필드를 나타내며 $i, 위의 다음 2개 스크립트와 같이 스크립트에서 해당 필드를 참조하지 않으면 대부분의 awk는 각 레코드를 필드로 분할하는 데 시간이 걸리지 않습니다.
  3. $0필드를 변경하기 위해 호출될 때마다 sub()awk가 필드에서 다시 빌드되도록 강제합니다 (즉, 행당 최대 NF 번).

답변4

사용행복하다(이전 Perl_6)

<(…)>캡처 태그 사용 :

~$ raku -pe "s:g/  [ ^ | \| ]  <( \' )> //;"  file

#OR

~$ raku -pe 's:g/  [ ^ | \| ]  <( \c[APOSTROPHE] )> //;'  file

또는앞으로 되돌아보기를 사용하십시오 <?after … >:

~$ raku -pe "s:g/  <?after ^ | \| >  \'  //;"  file

#OR

~$ raku -pe 's:g/  <?after ^ | \| >  \c[APOSTROPHE]  //;'  file

또는<!after … ><-[…]>부정적인 사용자 정의 문자 클래스 에 부정적인 뒤돌아보기를 사용하십시오.

~$ raku -pe "s:g/  <!after  <-[|]> >  \'  //;"  file

#OR

~$ raku -pe 's:g/  <!after  <-[|]> >  \c[APOSTROPHE]  //;'  file

또는사용 split/ join:

~$ raku -ne ".split(/ [ ^ | \| ] \'? /)[1..*].join('|').put"  file

#OR

~$ raku -ne '.split(/ [ ^ | \| ] \c[APOSTROPHE]? /)[1..*].join("|").put'  file

필요한 경우 위의 대괄호 그룹을 사용합니다(Raku의 대괄호는 를 잡지 않습니다 $0$1).


입력 예(빈 열에 대해서도 테스트):

'foo|'012|that's nice|bar||baz

출력 예(모든 예):

foo|012|that's nice|bar||baz

1 Perl 예제를 제공한 @StéphaneChazelas에게 감사드립니다.

https://docs.raku.org/언어/regexes
https://raku.org

관련 정보