CSV 파일이 있습니다.
1,abcde aa aaaa aaa aaaa abcde,4
2,efghi ooo oooo ooo oooo efghi,5
첫 번째와 마지막 5자로 두 번째 열을 자르고 3개의 점으로 채우려면 이 열이 필요합니다. 이 목표를 달성하는 방법은 무엇입니까?
1,abcde ... abcde,4
2,efghi ... efghi,5
답변1
해결책 sed
은
sed -E 's/(.*,.{5}).*(.{5},.*)/\1...\2/'
두 번째 "열"(필드)이 9자 이하이면 입력이 변경되지 않은 채로 유지되지만 …
정확히 10자라도 " "가 삽입됩니다(어떤 문자도 대체하지 않더라도).
입력하다 | 산출 |
---|---|
9,abcdefghi,z |
9,abcdefghi,z (잔돈은 그대로 유지해주세요) |
10,abcdefghij,z |
10,abcde...fghij,z (참고로 이건더 길게입력보다. ) |
캐스의 대답두 번째 필드가 대체할 가치가 있을 만큼 충분히 긴지 명시적으로 확인하는 것이 좋습니다. 내 대답은 질문을하는 것이기 때문에설명하다(점 3개 삽입) 표시되는 것(공백 + 점 3개 + 공백 삽입 또는 입력에 공백 남기기) 대신 처음 5개와 마지막 5개 사이에 4개 이상의 다른 문자가 있는 경우 혜택을 받습니다. 이 문제를 처리하려면 다음 명령을 사용할 수 있습니다.
sed -E 's/(.*,.{5}).{4,}(.{5},.*)/\1...\2/'
입력하다 | 산출 |
---|---|
10,abcdefghij,z |
10,abcdefghij,z (잔돈은 그대로 유지해주세요) |
13,abcdefghijklm,z |
13,abcdefghijklm,z (여전히 변화가 없음) |
14,abcdefghijklmn,z |
14,abcde...jklmn,z (입력한 문자보다 한 글자 더 짧습니다.) |
20,abcdefghijklmnopqrst,z |
20,abcde...pqrst,z |
.{4,}
4개 이상의 문자를 일치시킵니다. 물론 음수가 아닌 정수 4
로 변경할 . 예를 들어 반복되는 cas에 대해 제안된 답변을 사용하려면 를 min=20
사용합니다 .{11,}
.
답변2
$2가 잘라내려는 길이(15자: 5자 + 공백 + 3점 + 공백 + 5자)보다 길지 않으면 수행할 가치가 없습니다.
$ awk -F, '
BEGIN {OFS=FS; min=15};
length($2) > min { $2 = substr($2,1,5) " ... " substr($2, length($2)-4) }1' input.csv
1,abcde ... abcde,4
2,efghi ... efghi,5
3,short field,5
$ cat input.csv
1,abcde aa aaaa aaa aaaa abcde,4
2,efghi ooo oooo ooo oooo efghi,5
3,short field,5
또는 length($2)
각 입력 행에 대해 한 번만 계산합니다. (OFS 및 최소값을 설정하는 다른 방법도 표시됩니다.)
awk -F, -v OFS=, -v min=15 '
{ L=length($2) };
L > min { $2 = substr($2,1,5) " ... " substr($2, L-4) }1' input.csv
1 그보다 훨씬 길지 않으면 수행할 가치가 없을 것입니다. 따라서 최소 20자 정도일 것입니다.
답변3
현재 예에서 필요한 것은 다음과 같습니다.
$ sed 's/ .* / ... /' file
1,abcde ... abcde,4
2,efghi ... efghi,5
또는 실제로 두 번째 필드에서만 작업해야 하는 경우 다음을 수행하세요.
$ awk 'BEGIN{FS=OFS=","} {sub(/ .* /," ... ",$2)}1' file
1,abcde ... abcde,4
2,efghi ... efghi,5
이것이 필요한 전부가 아니라면 질문을 편집하여 적용되지 않는 경우를 포함하여 더욱 대표적인 입력/출력 예제를 표시하십시오.
답변4
사용행복하다(이전 Perl_6)
raku -pe 's/ \, <( (<alnum>**5) .* (<alnum>**5) )> \, /$0 ... $1/;'
또는
raku -pe 's/ \, <( $<head>=[<alnum>**5] .* $<tail>=[<alnum>**5] )> \, /$<head> ... $<tail>/;'
입력 예:
1,abcde aa aaaa aaa aaaa abcde,4
2,efghi ooo oooo ooo oooo efghi,5
출력 예(위의 두 코드 예):
1,abcde ... abcde,4
2,efghi ... efghi,5
위의 답변은행복하다프로그래밍 언어는 Perl 프로그래밍 언어 계열에 속합니다. 위의 두 답변은 기본적으로 column_1의 쉼표 오른쪽에 있는 처음 5자가 <alnum>
(문자 + 밑줄 + <digits>
)라는 가정을 기반으로 합니다. 더 넓은 범위의 문자를 처리하는 방법에 대한 자세한 내용은 아래 코드를 참조하세요.
Raku는 더욱 강력하고 읽기 쉽도록 설계된 새로운 정규식 엔진을 사용합니다. 첫 번째 예에서는 번호가 매겨진 캡처( $0
, $1
)가 사용되는 반면, 두 번째 예에서는 캡처( $<head>
, $<tail>
)가 사용됩니다. 위 코드의 하이라이트에는 1) 숫자가 아닌 문자를 현명하게 이스케이프 처리 \,
(추측할 필요가 없음), [ … ]
정규식 "원자"를 대괄호로 그룹화, ( … )
대괄호로 캡처, 처음부터 번호 매기기 캡처 , 일반 수량 $0
자로 사용 ( **min..max
예: **5
), 캡처 마커를 사용하여 일치 개체 외부의 텍스트를 묘사합니다 <( … )>
. 그러면 쉼표(일치 개체 외부)가 실수로 제거되지 않습니다.
위의 답변은 (문자, 밑줄) + 로 구성된 Raku의 내장 <alnum>
문자 클래스를 사용합니다 . 그러나 더 다양한 문자를 잘라낼 수도 있습니다. 내장 문자 클래스를 사용자 정의(사용자 정의 및/또는 열거형) 문자 클래스로 교체해 볼 수 있습니다 . 사용자 정의 문자 클래스는 공백이 아닌 문자(예: 숫자의 소수점)에서 쉼표를 빼고 마이너스 쉼표를 사용 합니다 .<alpha>
<digits>
<alnum>
<+[\S]-[,]>
<+[\S]-[,]>
+[\S]
-[,]
아래에는 합리적인 결과가 나와 있습니다. 예를 들어 1행과 2행은 적절하게 단축된 반면 line_3/column_2(쉼표가 아닌 문자 4개만 길이)는 너무 짧아서 더 이상 잘릴 수 없습니다. (“단거리 필드” 영감을 주신 @cas에게 감사드립니다):
raku -pe 's/ \, <(( <+[\S]-[,]>**5) .* ( <+[\S]-[,]>**5 ))> \, /$0 ... $1/;'
입력 예:
1,$2.37 aa aaaa aaa aaaa abcde,1_end
2,##IN: ooo oooo ooo oooo efghi,2_end
3,#OUT, ooo oooo ooo oooo efghi,3_end
4,short field,4_end
5,thin ice,5_end
예제 출력:
1,$2.37 ... abcde,1_end
2,##IN: ... efghi,2_end
3,#OUT, ooo oooo ooo oooo efghi,3_end
4,short ... field,4_end
5,thin ice,5_end