ゲームに必要なマテリアルのリストを、一番上から最も原始的なマテリアルまでまとめました。しかし、今は数字を集計する簡単な方法を探しています。
21 reinforced alloy
21 damascus steel
21 steel
21 iron dust
21 carbon
21 iron
21 iron dust
21 carbon
21 iron
21 hardened metal
21 damascus steel
21 steel
21 iron dust
21 carbon
21 iron
21 iron dust
21 carbon
21 iron
21 duralmin
21 aluminum dust
21 copper dust
21 aluminum
21 aluminum dust
21 compressed carbon
84 carbon
21 aluminum bronze
21 aluminum dust
21 bronze
21 copper dust
21 tin dust
21 copper
21 aluminum
21 aluminum dust
21 corinthian bronze
21 silver dust
21 gold dust
21 copper dust
21 bronze
21 copper dust
21 tin dust
21 copper
21 solder
21 lead dust
21 tin dust
21 lead
21 lead dust
21 billon
21 silver dust
21 copper dust
21 silver
21 silver dust
21 gold 24 carat
収集すべき原材料を探しているので、トップレベルは重要ではありません。たとえば、21 hardened metal
およびは21 damascus steel
合計を探しているため重要ではありません42 damascus steel
。42 iron dust
42 carbon
42 iron
これまで私正規表現テストウェブサイトgrep
しかし、最終的には計算のためにウェブサイトを開く必要がないように使用できるようになることを願っています。私は「炭素が5回現れ、これが一致する線です」のようなものを手に入れたいです。炭素が5回現れ、そのうち4番が現れて21 carbon
1番があることが分かれば、84 carbon
総必要量を簡単に計算できるので、より簡単に計算できます21*4 + 84 = 168 carbon
。
私は他の行がなく、その後に多数のタブがある行の数を数えようとしています。もしあれば、それは生ではないからです。
/(\t+)\d+ aluminum\n(?!\1)/g
(「アルミニウム」を私が探している原材料に置き換えます)
しかし、これは何も判明していません。正規表現を使用して達成したい目標を達成する方法はありますか?それでは、どうすればいいですか?
時間をいただきありがとうございます。
これをSOに置くかSEに置くかはよく分からないが、結局は使えるようになることを望むという点を考慮すれば、そこがgrep
より適切な場所ではないかと思います。
答え1
Perlに似た正規表現を使用するには、実際の正規表現を使用することをお勧めします。
<your-file perl -l -0777 -ne '
while (m{^(\s*+)(\d+) (.*)$(?!\n\1\s)}mg) {
$count{$3} += $2
}
END {
printf "%4d %s\n", $count{$_}, $_ for sort keys %count
}'
これは作る:
84 aluminum dust
168 carbon
42 copper
105 copper dust
21 gold 24 carat
21 gold dust
84 iron
84 iron dust
42 lead dust
63 silver dust
63 tin dust
-0777 -n
入力全体が吸収されることを意味します$_
。演算子の最終フラグは、始まりと終わりだけでなく、m
各行の始まりと終わりにも一致を生成します。フラグがない場合は改行に一致するものはありませんが、入力に空白行がある場合はここで問題が発生する可能性があることに注意してください。m{...}
^
$
$_
$_
s
.
\s
\s*+
はい、遡及適用されていないバージョンです\s*
。\d+
( ) 後の内容は空白と一致できないため必ずしも必要ではありません。
Standardは、grep
使用中のようなperlに似た正規表現と\d
perl RE演算子をサポートしていませんが、複数行モードもサポートするものを使用できます。(?!\1)
pcregrep
-o
-M
<your-file pcregrep -Mo '^(\s*+)\K.*$(?!\n\1\s)'
perl
合計計算などの他の作業にはまだパイプが必要なため、すべてのタスクにパイプを使用するよりも利点はawk
ほとんどperl
ありません。
インデントをタブとスペースと混在させることができる場合は、入力をこれらのいずれかを渡すか、expand
最初にunexpand
スペースまたはタブにマージできます。基本的に、彼らはタブストップをほとんどの端末やブラウザのように8列と見なしますが(Stackexchangeを除いて面倒なことに4列になります)、-t
これを変更するオプションを参照してください。
答え2
行のレベル<=次の要素のレベルの場合、行は「プレミア」です。これは次のとおりです。
前の行は、そのレベル<=現在のレベルの場合(または最後の行の場合)の最初の行です。
NF
最後のフィールドとして、フィールド区切り文字「\ t」、level、およびコンポーネントでawkを使用します$NF
。
awk -F '\t' 'prevlev>=NF {print primi};
{prevlev = NF; primi=$NF }
END {print $NF}'
要約すると、次の内容を実行できます。
... | sed 's/ /\t/' | datamash -g 2 -s sum 1
答え3
LookbehindとLookaheadを使用する必要があります。また、1行ずつ処理するのではなく、入力全体を一緒に処理する必要があります。次のコマンドは必要な操作を実行する必要があります。
grep -Pzo '(?<=\n)(\s+)(\S[^\n]*)(?!\n\1\s)' input_file
-P
Perl構文を有効にします。-z
改行文字の代わりにヌル終端を使用してください。-o
一致する項目のみが出力されます。(?<=\n)
改行を見つけてください。代わりに^
、通常は各行の先頭に一致します。後続の否定的な見解を使用してください(?<!...)
。おそらく常により深いレベルがあるので、最初の行を無視します。そうでない場合は、送信する前に入力の先頭に新しい行を追加できますgrep
。これを行うより良い方法があるかもしれませんが、以下は一つです。( echo ; cat input_file ) | grep ...
(\s+)
インデントレベルをキャプチャします。これは後で呼び出されます\1
。\s
スペースと一致します。これに対する潜在的な問題の1つは、改行文字がインデントの一部と見なすことができることです。たとえば、二重改行は段落区切り文字としてよく使用されます。\s
インデントに使用したい特定のスペース()に置き換えることができます[\ \t]
。(\S[^\n]*)
興味のあるテキストをキャプチャします。\S
空白でないものと一致します。[^\n]
改行文字以外のすべての文字と一致します。(?!\n\1\s)
否定的なプレビューは、次の行が現在の行より深くインデントされないようにします。肯定的な見通しが必要な場合はを使用してください(?=...)
。