文字列内の位置に基づいて可変数の先行ゼロを追加する拡張正規表現を実装する


10

数値の体系的なスキームにさまざまな数の先行ゼロを追加するために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

ただし、私が探しているのは、フィールド2と3に最大2桁、フィールド4に最大3桁をゼロで埋めて、すべてのアイテムが[0-9]。[0-9]で標準の長さになるようにすることです。 2}。[0-9] {2}。[0-9] {3}

1.01.01.001,Some Text Here

私の人生では、境界を変更して、ピリオドに続く数字のみにスナップするために必要なパラメーターを含める方法すら理解できません。私は理解している\ 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/.//' しかし、よりエレガントなアプローチがあるかどうか知りたいです。
だいじざい2017

1
奇妙なことに、文字列を逆にして、末尾のゼロを適用し、結果を逆にすると、目的をより簡単に達成できる場合があります。
roaima

2
使用printf(またはprintfAwk内の呼び出し)の方が簡単かもしれません。
ワイルドカード2017

1
これは間違いなく将来、awkやperl(またはprintfと簡単なフィールド分割を備えた他の言語)のような言語で実装、読み取り、理解、および変更するのが容易になるものです。
cas

1
@ワイルドカード-よく理解されたポイント。sedのデバッグについて何か教えてもらえますか?通常、私は、長々しい言葉に句読点を付けて長時間見つめます。;)それを除いて、私は時々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. 最初の置換では、各数値に特定の量のゼロを追加します。1ゼロから2および3の数値、2ゼロから4の数値。重要ではありません、すでに何桁あるか。
  2. 2番目のサブスチューデントは、余分なゼロをすべて削除し、必要な数の数値のみを残します。2と3の数字は2桁のみである必要があります。それらを残し、残りを削除します。4番目の数値は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

結局私は便宜のためにこれをPythonでスクリプト化することになりましたが、perlが以前に(少なくとも)出力からバックスラッシュを削除したことを考えると、これは書かれた私の質問に対する最良の答えです。この1.はsedソリューションであり、2.はテキストを悪用することなく適切な出力を生成します。回答としてマーク。ありがとう!:-)
daijizai 2017

@daijizaiはすでに説明したように、このperlバージョンではバックスラッシュが削除されません。
roaima 2017

9

bashはこれを処理できます。ただし、perlよりもかなり遅くなります。

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ます。)また、シェルループを使用してテキストを処理することが悪い習慣と見なされている理由
ワイルドカード2017

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に移動しようとしていました。法案に合うようです。確認して戻ってきます。
だいじざい2017

@daijizai awkも機能します-同じ原理を使用printf
roaima

これが失敗する唯一のことは、私が予想することはできませんでしたが、重要です。テキスト部分からバックスラッシュを取り除いているようです。
だいじざい2017

@daijizaiはここにはありません。どのようにテキストにバックスラッシュを付けていますか?バックスラッシュ付きの例を追加しました
roaima

私の内部データセットで使用すると、SOME \ Text \ Might \ Be \ Here \ 4Realzのような文字列を含むテキスト列を持つ行があります。このデータセットはperlの声明に渡されたとき、それはSOMETextMightBeHere4Realzのような応答が生じた
daijizai

3

考えられるアプローチの1つを次に示します。
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、Some Text Hereになった:1.1.101.11001、Some Text Here
daijizai

@daijizai私の編集を見てください。これは要件を満たしますか?
maulinglawns 2017

残念ながらそうではありませんが、それは私のせいかもしれません。ゼロ埋めの必要性は、フィールド2と3で2桁上、フィールド4で3桁になる必要があります。基本的には[0-9]。[0-9] {2}。[0-9] {2}。[0 -9] {3}、Some Text Here
daijizai

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

説明:

ここで使用する方法は、数値の近傍を調べ、それに基づいてアクションを実行することです。したがって、2番目と3番目の数値は両側にドットが表示され、4番目の数値は左側にドットが表示され、右側にコンマが表示されます。

$ 1は、正規表現が2番目または3番目の数値のパスを取得するときに設定されます。したがって、精度のパディングは2です。OTOH、4番目の数値の場合、パディングは3です。

%cat file.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.