web-dev-qa-db-ja.com

bashを使用して、数字と文字列を1行から分離する

Bashコマンドを使用して文字列と数値を1行から分離する方法。

例:私は含む文字列を持っています

string123anotherstr456thenanotherstr789

出力は次のようになります。

string
123
anotherstr
456
thenanotherstr
789
6
HUY

GNU grepまたは互換性のあるソリューション:

s="string123anotherstr456thenanotherstr789"
grep -Eo '[[:alpha:]]+|[0-9]+' <<<"$s"
  • [[:alpha:]]+|[0-9]+-正規表現の代替グループ。アルファベット文字または数字のいずれかに一致します。両方とも、出力では別個のエントリーと見なされます

出力:

string
123
anotherstr
456
thenanotherstr
789
20
RomanPerekhrest

POSIXly:

string=string123anotherstr456thenanotherstr789
sed '
  s/[^[:alnum:]]//g; # remove anything other than letters and numbers
  s/[[:alpha:]]\{1,\}/&\
/g; # insert a newline after each sequence of letters
  s/[0-9]\{1,\}/&\
/g; # same for digits
  s/\n$//; # remove a trailing newline if any' << EOF
$string
EOF
5

awk

入力には文字と数字のみが含まれています

[[:alpha:]]+(文字のシーケンス)ごとと[[:digit:]]+(数字のシーケンス)ごとに改行文字を追加します。

awk '{ gsub(/([[:alpha:]]+|[[:digit:]]+)/,"&\n",$0) ; printf $0 }' filename

&は、一致したシーケンスのawk省略形です。)


入力に他の文字(句読点など)が含まれています

以前と同じように、ただし[^[:alnum:]]+(非文字、非数値)文字の部分文字列も処理するようになりました:

awk '{ gsub(/([[:alpha:]]+|[[:digit:]]+|[^[:alnum:]]+)/,"&\n",$0) ; printf $0 }' filename

負の数と小数

-(ハイフン)と.(ピリオド)を数値として扱う:

awk '{ gsub(/([[:alpha:]]+|[[:digit:].-]+|[^[:alnum:].-]+)/,"&\n",$0) ; printf $0 }' filename

これらの文字は、[[:digit:].-]+[^[:alnum:].-]+の両方の式に出現する必要があります。また、リテラルハイフンとして解釈するには、-が各式の最後の右角かっこの前のlast文字である必要があります。それ以外の場合は、文字の範囲を示します。

例:

[test]$ cat file.txt 
string123another!!str456.001thenanotherstr-789

[test]$ awk '{ gsub(/([[:alpha:]]+|[[:digit:].-]+|[^[:alnum:].-]+)/,"&\n",$0) ; printf $0 }' file.txt 
string
123
another
!!
str
456.001
thenanotherstr
-789

読者のための演習

入力ファイルで必要な場合は、awkコマンドを次のように変更できます。

  • -が数値シーケンスのstartで発生する場合にのみ、数値の一部としてカウントされることを確認します。
  • 科学表記法で表現された数値を許可します。
4
Gaultheria

GNU sed(または互換性のある)ソリューション:

s="string123anotherstr456thenanotherstr789"
sed 's/[a-zA-Z]*\|[0-9]*/&\n/g; s/\n$//' <<<"$s"

出力:

string
123
anotherstr
456
thenanotherstr
789
3
RomanPerekhrest

python3

python3 -c '
from itertools import groupby
s = ("".join(g) for k, g in 
    groupby("string123anotherstr456thenanotherstr789", lambda x: x.isalpha()))
print(*s, sep="\n")
'

string
123
anotherstr
456
thenanotherstr
789
2
iruvar

同じことを達成するために、1つのライナーの下で使用されます。テストされたように、それはうまくいきました

sed "s/[0-9]\{3\}/\n&/g" filename | sed "s/[0-9]\{3\}/&\n/g"| sed '/^$/d'

出力

string
123
anotherstr
456
thenanotherstr
789
2

私はまだPerlソリューションを見ていないので、ここに:

_$ cat s
string123anotherstr456thenanotherstr789
$ Perl -lne 'print $& while /[[:alpha:]]+|[[:digit:]]+/g' < s
string
123
anotherstr
...
_

もちろん、「数値」のより広い定義では、_[-+]?[0-9]+_(先行符号)、[-+]?[0-9]+(.[0-9]+)?(オプションの小数部)、または[-+]?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?(プラスオプションの指数)。後者の2つには、小数点がある場合、小数点の前後に少なくとも1桁必要です。

1
ilkkachu

ピュアバッシュ

これは、元の文字列のいくつかの(短い)コピーを作成するため、比較的非効率的です。

declare s=string123anotherstr456thenanotherstr789
while [[ "$s" =~ ^([a-z]+)([0-9]+) ]]; do
  echo ${BASH_REMATCH[1]}
  echo ${BASH_REMATCH[2]}
  s="${s:${#BASH_REMATCH[0]}}"
done

1行あたり何組の文字と数字のペアを扱っていますか?

1
Luchostein
gawk '{ $1 = $1; print }' FPAT='[a-z]+|[0-9]+' OFS='\n' input.txt

テスト

gawk '{ $1 = $1; print }' FPAT='[a-z]+|[0-9]+' OFS='\n' <<< 'string123anotherstr456thenanotherstr789'

出力

string
123
anotherstr
456
thenanotherstr
789
1
MiniMax