次のテキストファイルがあります。
tech -this is sample and ... 1.2 sample
bla bla bla test tech 1 one two
foo bar foo bar tech and [email protected] 0.1
bar bar bar foo foo tech 10.1.3
tech 7.5 and continue this line
sample_test one two tech 8.0
one two there tech 0.x *sample bla bla
www sample tech 1.3.x foo bar $foo #bar
foobar barbar bla bla tech 5.x
tech testtest 2.0.4x this is sample
サンプルテキストを抽出したい - 次の単語科学技術そしてこのような数字パターン7.5その他のデジタルモード。
(実際には、数値パターンはバージョン管理スタイルのバージョン番号です)
次に、次のように出力を取得します。
tech 1.2
tech 1
tech 0.1
tech 10.1.3
tech 7.5
tech 8.0
tech 0.x
tech 1.3.x
tech 5.x
tech 2.0.4x
答え1
仮説
入力は、スペース文字シーケンス(スペースではなく文字シーケンス)で区切られた文字列を含むテキストファイルです。各行には特定の単語(ランタイムで知られている)が含まれ、その後にはバージョン番号形式の数値文字列が続きます(すぐには必要ありません)。 (明らかにこれは数字で始まるという意味です。)
実行時に引数として検索する単語を指定できる必要があります。たとえば、次の単語を検索するには科学技術、私たちは話すことができなければなりません
word=tech
コマンド(またはスクリプト)を使用するようにします$word
。たとえば、「technology」、「nanotech」、「Tech」は一致しないでください。単語には文字、数字、_
および(アンダースコア)(句読点、正規表現の特殊文字)のみを含める必要があり、これにより不要な結果が生じる可能性があります。各限られた行に対して、コマンドはスペースで区切られた単語と数字を出力する必要があります。ファイルにこれらの前提条件を満たさない行が含まれている場合(たとえば、必要な単語や数字が含まれていない)、動作は定義されません。特に、これらの故障ラインは単に無視することができる。
以下のすべてのコマンド
$word
は上記のように定義されていると仮定します。
注:これらの各コマンドはさまざまな方法で表現できます。場合によっては、その違いはわずかです。
grep
明らかにgrep
私は何をすべきかわかりません。
シンプルgrep
で役に立つ
注文する
grep "\<$word\>\|\<[[:digit:]][[:graph:]]*\>"
以下を含むすべての行と一致します。誰でも単語(\<$word\>
)または(\|
)数字(\<[[:digit:]][[:graph:]]*\>
)。 ([[:graph:]]
文字、数字、または句読点、つまりスペースを除くすべての文字を表します。)--color
モードでは、このコマンドの出力は少し面白いです。
grep -o "\<$word\>\|\<[[:digit:]][[:graph:]]*\>"
一致するすべての文字列を印刷し、一致する文字列のみを印刷します。ひも— 別の行に:
tech
1.2
tech
1
tech
0.1
tech
10.1.3
tech
7.5
tech
8.0
tech
0.x
tech
1.3.x
tech
5.x
tech
2.0.4x
だから私たちはこうします。
grep -o "\<$word\>\|\<[[:番号:]][[:Graphic:]]*\>"(入力ファイル)| sed "/$単語/ { N; s/\n/ / }"上記の出力を取得して単語をリンクします(科学技術)と次の行(スペースで区切ります):
tech 1.2
tech 1
tech 0.1
tech 10.1.3
tech 7.5
tech 8.0
tech 0.x
tech 1.3.x
tech 5.x
tech 2.0.4x
pcregrep
pcregrep -o1 -o2 --om-separator=' ' "\b($word)\b.*?\b(\d\S*)"
単語を一致そして数字(\b
単語の境界、
\d
数字、スペースを除くすべての文字)は...グループ\S
からそれぞれをキャプチャします。その後、一致する文字列のみを出力します。ただし、出力キャプチャグループ1と2と言うことができます。当然、文字列の間に何を入れるかを指定してください。(
)
-o
pcregrep
-o1 -o2
--om-separator=' '
注:ここでは(貪欲ではない一致)を使用するため、.*?
入力行に複数の数字がある場合は、最初の数字が検索されます。他のコマンドは最後のコマンドを探します。
sed
sed -n "s/.*\(\<$word\>\).*[[:blank:]]\(\<[[:digit:]][[:graph:]]*\).*/\1 \2/p"
そのコマンドと同様に、pcregrep
このコマンドはキャプチャグループの文字列と一致し、それを\1 \2
。
awk
awk -v the_word="$word" '
{
w=0 # Index of word
n=0 # Index of number
for (i=0; i<=NF; i++) {
if ($i == the_word) w=i
if (substr($i,1,1) ~ /[[:digit:]]/) n=i
}
if (w>0 && n>w) print $w, $n
}'
the_word
その後、単語()と数字(最初の文字が数字の文字列)を見つけます。見つかったら、順番に印刷します。
注:単語は完全に独立している場合にのみ認識されます。句読点に達すると、他のコマンドも一致します。
The cyber clock goes tech, tock …
This contains the word (tech) …
答え2
以下のコードは望ましい効果を達成する必要があります。
searchword="tech"
(cat << EOF
tech -this is sample and ... 1.2 sample
bla bla bla test tech 1 one two
foo bar foo bar tech and [email protected] 0.1
bar bar bar foo foo tech 10.1.3
tech 7.5 and continue this line
sample_test one two tech 8.0
one two there tech 0.x *sample bla bla
www sample tech 1.3.x foo bar $foo #bar
foobar barbar bla bla tech 5.x
tech testtest 2.0.4x this is sample
EOF
) | grep $searchword |\
grep -o '\b[0-9x][0-9x]*\b\|\b[0-9][0-9]*\.[0-9x][0-9x]*\b\|\b[0-9][0-9]*\.[0-9][0-9]*\.[0-9x][0-9x]*\b' |\
sed "s/^/$searchword /"
あなたを連れてくるだろう
tech 1.2
tech 1
tech 0.1
tech 10.1.3
tech 7.5
tech 8.0
tech 0.x
tech 1.3.x
tech 5.x
tech 2.0.4x
少なくとも
- 強く打つ
GNU bash, version 4.4.5(1)-release
- sed
sed (GNU sed) 4.2.2
- grep
grep (GNU grep) 2.27
この回答が役に立ちました。それ以外の場合は、質問をより明確かつ説明しやすくすることができます。
答え3
grepやsedではこれを得ることはできませんが、Perlは助けます:
$ perl -e 'while($stdin = <>) {@matches = $stdin =~ /(tech)[^0-9]*([0-9x][0-9x.]*)/g; print "@matches\n" if @matches}' < INPUTFILE
これは< INTPUTFILE
stdinを介してスクリプトにファイルを入力した場合にのみ機能します。 stdinは他のソース(パイプ、<<<
文字列リダイレクトなど)から提供できます。
説明する:
#一致に使用する変数に標準入力(Perl)を割り当てます。 #入力が空の場合(例:EOF)を検出します。 中 ($stdin = ) { # @matches 配列に $stdin に一致を割り当てます。 #/(技術)[^0-9]*([0-9x][0-9x.]*)/g; #(tech):「tech」という用語と一致し、()は@matchesに入れます。 # [^0-9]*: .* があまりにも貪欲であるため、数字ではなく数字と一致すると破棄されます。 #最後の数字と一致 #([0-9x] [0-9x.] *):0、0.x、0.9.xなどのパターンを一致させ、()@matchesに入れます。 @matches = $stdin =~ /(tech)[^0-9]*([0-9x][0-9x.]*)/g; # @matchesが空でない場合は、上記の配列を表示します。 @matchesの場合は、「@matches \ n」を印刷します。 }
ファイルに適用すると、出力は次のようになります。
技術1.2 技術1 技術0.1 技術10.1.3 技術7.5 技術8.0 技術1.3.x 技術5.x 技術2.0.4x