문자열의 위치에 따라 가변적 인 선행 0을 추가하기 위해 확장 정규 표현식 구현


10

숫자 조직 구성표에 다양한 수의 선행 0을 추가하기 위해 sed 구문을 다운시키는 데 문제가 있습니다. 내가 운영하는 문자열은 다음과 같습니다.

1.1.1.1,Some Text Here

sed 구문 활용

sed -r ":r;s/\b[0-9]{1,$((1))}\b/0&/g;tr"

응답을 이끌어 낼 수 있습니다

01.01.01.01,Some Text Here

그러나 내가 찾고있는 것은 모든 항목의 표준 길이가 [0-9]에 있도록 필드 2와 3에서 최대 2 자리, 필드 4에서 3 자리까지 0으로 채우는 것입니다. [0-9] { 2}. [0-9] {2}. [0-9] {3}

1.01.01.001,Some Text Here

내 인생에서 나는 마침표 뒤에 오는 숫자에만 스냅하는 데 필요한 매개 변수를 포함하도록 경계를 수정하는 방법조차도 알 수 없습니다. 단어 경계에서 0 문자와 일치하는 것으로 이해하는 \ b를 사용하는 것과 관련이 있다고 생각하지만 일치에 마침표를 추가하려는 시도가 다음과 같이 실패하는 이유를 이해하지 못합니다.

sed -r ":r;s/\.\b[0-9]{1,$((1))}\b/0&/g;tr"
sed -r ":r;s/\b\.[0-9]{1,$((1))}\b/0&/g;tr"
Both cause the statement to hang

sed -r ":r;s/\b[0-9]\.{1,$((1))}\b/0&/g;tr"
sed -r ":r;s/\b[0-9]{1,$((1))}\.\b/0&/g;tr"
sed -r ":r;s/\b[0-9]{1,$((1))}\b\./0&/g;tr"
cause the statement to output:

1.01.01.1,Some Text Here

또한 진술에 다음과 같은 텍스트가 포함되어 있으면 추가 문제가 발생할 것으로 예상합니다.

1.1.1.1,Some Number 1 Here

sed와 그 모든 복잡성을 실제로 배워야한다는 것은 명백한 결론입니다. 나는 그 일을하고 있지만이 특정 진술이 계속해서 문제를 일으킬 것으로 기대합니다. 도움을 주시면 감사하겠습니다.

편집 : 나는 방법을 알아 냈습니다 ...이 진술은 내가 찾고있는 것을하는 것처럼 보이지만 이것을 수행하는보다 우아한 방법이 있어야합니다.

sed -r ':r;s/\b[0-9]{1,1}\.\b/0&/;tr;:i;s/\b[0-9]{1,2},\b/0&/;ti;s/.//'

또한 텍스트에 비슷한 숫자 형식이 표시되면 구문 상 문제가 발생할 수 있습니다.

1.1.1.1,Some Text Referring to Document XXX Heading 1.2.3

이 경우 다음과 같은 결과가 발생합니다.

1.01.01.001,Some Text Referring to Document XXX Heading 01.02.03

해결 도와 주셔서 감사합니다. 처음에 아래에서 수락 한 답변으로 문제를 해결했습니다. 아래 정렬을 활용하여 더 큰 솔루션의 일부로 솔루션을 Python으로 옮겼습니다.

def getPaddedKey(line):
    keyparts = line[0].split(".")
    keyparts = map(lambda x: x.rjust(5, '0'), keyparts)
    return '.'.join(keyparts)

s=sorted(reader, key=getPaddedKey)

이것은 내가 찾고있는 것을하는 것 같습니다 : sed -r ':r;s/\b[0-9]{1,1}\.\b/0&/;tr;:i;s/\b[0-9]{1,2},\b/0&/;ti;s/.//' 그러나 더 우아한 접근법이 있는지 알고 싶습니다.
daijizai

1
이상하게도 문자열을 반전시키고 후행 0을 적용한 다음 결과를 반전하면보다 쉽게 ​​목표를 달성 할 수 있습니다.
roaima

2
사용 printf(또는 printfAwk 내 전화)이 더 간단 할 수 있습니다.
와일드 카드

1
이것은 확실히 awk 또는 perl과 같은 언어 (또는 printf 및 쉬운 필드 분할이있는 다른 언어)로 미래에 구현, 읽기, 이해 및 수정하기가 더 쉬운 것입니다.
cas

1
@Wildcard-잘 찍은 포인트. sed 디버깅에 대해 설명해 주시겠습니까? 일반적으로, 나는 expletives에 의해 구두점을 두는 연장 된 응시에 의지한다. ;) 그 말을 제외하고는 때때로 sed 문을 더 작은 조각으로 나누고 각 문을 다시 결합하기 전에 작동하도록 노력합니다. 나는 최근에 훌륭한 튜토리얼 github.com/learnbyexample/Command-line-text-processing/blob/…를 읽었 으며 연장 된 응시를 적용 할 때까지 일부 예제가 잘못되었다고 확신했습니다.
Joe

답변:


4

용법: leading_zero.sh input.txt

#!/bin/bash

sed -r '
    s/\.([0-9]{1,2})\.([0-9]{1,2})\.([0-9]{1,3},)/.0\1.0\2.00\3/
    s/\.0*([0-9]{2})\.0*([0-9]{2})\.0*([0-9]{3})/.\1.\2.\3/
' "$1"

설명:

  1. 첫 번째 치환은 각 숫자에 일정한 양의 0을 더합니다. 1 0 ~ 2 및 3 숫자, 2 0 ~ 4 숫자. 아무리 많은 숫자가 이미 있는지는 중요하지 않습니다.
  2. 두 번째 substution은 여분의 0을 모두 제거하고 필요한 수의 숫자 만 남겨 둡니다. 2와 3 숫자는 2 자리 숫자 만 포함해야합니다. 그들을 떠나 휴식을 제거합니다. 네 번째 숫자는 3 자리 숫자 만 포함해야합니다. 그들을 떠나 휴식을 제거합니다.

input.txt

1.1.1.1,Some Text Here
1.1.1.1,Some Text Here
1.11.1.11,Some Text Referring to Document XXX Heading 1.2.3
1.1.1.1,Some Text Here
1.1.11.111,Some Text Referring to Document XXX Heading 1.2.3
1.11.1.1,Some Text Here

output.txt

1.01.01.001,Some Text Here
1.01.01.001,Some Text Here
1.11.01.011,Some Text Referring to Document XXX Heading 1.2.3
1.01.01.001,Some Text Here
1.01.11.111,Some Text Referring to Document XXX Heading 1.2.3
1.11.01.001,Some Text Here

결국 파이썬에서 편의를 위해 이것을 스크립팅하는 것으로 끝났지 만, 이것은 이전에 제출 된 펄이 출력에서 ​​백 슬래시를 제거했다는 점을 감안할 때 작성된 질문에 대한 가장 좋은 대답입니다. 이것은 1. sed 솔루션이며, 2. 텍스트를 성가 시게하지 않고 적절한 출력을 생성합니다. 답변으로 표시 감사! :-)
daijizai

이미 설명했듯이 @daijizai perl버전은 백 슬래시를 제거하지 않습니다.
roaima

9

bash는 이것을 처리 할 수 ​​있습니다. 그래도 펄보다 훨씬 느릴 것입니다 :

echo "1.1.1.1,Some Text Here" | 
while IFS=., read -r a b c d text; do
    printf "%d.%02d.%02d.%03d,%s\n" "$a" "$b" "$c" "$d" "$text"
done
1.01.01.001,Some Text Here

2
아니면 Awk. 그러나 printf현명한 도구 인를 사용하는 경우 +1입니다 . (Awk은 텍스트 처리 printf보다 설계가 더 우수 bash합니다.) 또한 왜 쉘 루프를 사용하여 텍스트를 처리하는 것이 나쁜 습관으로 간주됩니까?를
와일드 카드

5

구체적으로 perl해결책을 요구하지 않았지만 여기에 해결책이 있습니다. 개인적으로 나는 이것이 여러 줄로 나눌 때 조금 더 읽기 쉽다고 생각합니다.

먼저 하나의 라이너가 있습니다.

(
    echo '1.2.3.4,Some Text Here'
    echo '1.01.01.1,Some Text Here'
    echo '1.1.1.1,Some Number 1 Here'
    echo '1.1.1.1,Some Text Referring to Document XXX Heading 1.2.3'
    echo '1.2.3.4,Some \n \s \text'
) |
perl -ne '($ip, $text) = split(/,/, $_, 2); $ip = sprintf("%1d.%02d.%03d.%03d", split(/\./, $ip)); print "$ip,$text"'

결과 :

1.02.003.004,Some Text Here
1.01.001.001,Some Text Here
1.01.001.001,Some Number 1 Here
1.01.001.001,Some Text Referring to Document XXX Heading 1.2.3
1.02.003.004,Some \n \s \text

그리고 여기에 perl스크립트가 깨져 주석 처리되어 있습니다 ( -n플래그 while read; do ... done는 코드 주위에 암시 적 루프를 넣습니다 ).

($ip, $text) = split(/,/, $_, 2);                # Split line into two parts by comma
@octets = split(/\./, $ip)                       # Split IP address into octets by dots
$ip = sprintf("%1d.%02d.%03d.%03d", @octets);    # Apply the formatting
print "$ip,$text"                                # Output the two parts

아이러니하게도, 나는 sed를 포기하고 이것을 게시했을 때 awk로 옮겼습니다. 계산서에 맞는 것 같습니다. 내가 확인하고 돌아올 게
daijizai

@daijizai awk도 작동합니다-동일한 원리를 사용하여printf
roaima

이것이 실패한 것은 예상 할 수 없었지만 중요합니다. 텍스트 부분에서 백 슬래시를 제거하는 것 같습니다.
daijizai

@daijizai 여기에 없습니다. 백 슬래시로 텍스트를 어떻게 공급합니까? 나는 당신을 위해 백 슬래시 예제를 추가했습니다
roaima

내부 데이터 세트와 함께 사용하면 SOME \ Text \ Might \ Be \ Here \ 4Realz와 같은 문자열을 포함하는 텍스트 열이있는 행이 있습니다. 이 데이터 셋이 perl 문에 전달되면 SOMETextMightBeHere4Realz
daijizai

3

가능한 접근 방법은 다음과 같습니다.
sed -E 's/([0-9]*\.)/0\1/g;s/.//;s/([0-9]*,)/00\1/'

echo "1.11.111.1111,Some Text Here" | sed -E 's/([0-9]*\.)/0\1/g;s/.//;s/([0-9]*,)/00\1/'
1.011.0111.001111,Some Text Here

이 문자열로도 작업하십시오.

echo "1.1.1.1,Some Number 1 Here" | sed -E 's/([0-9]\.)/0\1/g;s/.//;s/([0-9],)/00\1/'
1.01.01.001,Some Number 1 Here

... 그리고이 문자열 :

echo "1.2.2101.7191,Some Text Here" | sed -E 's/([0-9]*\.)/0\1/g;s/.//;s/([0-9]*,)/00\1/'
1.02.02101.007191,Some Text Here

불행히도 숫자가 올라감에 따라 고장납니다. 예를 들면 : 1.1.11.111, 일부 텍스트는 다음과 같습니다 : 1.1.101.11001, 일부 텍스트는
daijizai

@daijizai 내 편집 내용을 참조하십시오. 이것이 요구 사항을 충족합니까?
maulinglawns

불행히도, 나는 그것이 내 잘못이라고 생각합니다. 제로 채우기는 필드 2의 3 자리 숫자 2와 필드 4의 3 자리 숫자 2 자리 여야합니다. 기본적으로 [0-9]. [0-9] {2}. [0-9] {2}. [0 -9] {3}, 일부 텍스트 여기
daijizai

2
perl -pe '/^\d/g && s/\G(?:(\.\K\d+(?=\.))|\.\K\d+(?=,))/sprintf "%0".($1?2:3)."d",$&/ge'

설명:

여기에 사용 된 방법은 숫자의 주변을보고이를 기반으로 조치를 취하는 것입니다. 따라서 두 번째와 세 번째 숫자는 양쪽에 점이 표시되고 4 번째 숫자는 왼쪽에 점이 표시되고 쉼표는 오른쪽에 표시됩니다.

$ 1은 정규식이 두 번째 또는 세 번째 숫자의 경로를 취할 때 설정되며 그에 따라 정밀도 패딩은 2입니다. OTOH, 네 번째 숫자의 경우 패딩은 3입니다.

고양이 파일 % .txt

1.00.3.4,Some Text Here
1.01.01.1,Some Text Here
1.0.01.1,Some Number 1 Here
1.1.1.1,Some Text Referring to Document XXX Heading 1.2.3.4
1.2.3.4,Some \n \s \text

결과 :

1.00.03.004,Some Text Here
1.01.01.001,Some Text Here
1.00.01.001,Some Number 1 Here
1.01.01.001,Some Text Referring to Document XXX Heading 1.2.3.4
1.02.03.004,Some \n \s \text
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.