このような入力があります
LTCYMM SVNNDA DTVEV QLOPGO CUPUR
MMWVJM LIVLI WBSVD UQCMW HBMDA HVVFY BWYSS
NOGWOS JIKKDI GCIQAD MXJNWE SMVFCB GIZVPA GZOHZR WJBMZS
KKPQBP BKDKRU ZTPDPL ZRLUEL HRZZKO KXSKCU YZQTBT RISNKS
VYQQC BFAWI NSZDV HKPGI KVJOC COPPS
JGU YLN MXW ACR BZA HOP
TMCVPT HBNGIH IQYGCI DTQPON WXANKG GMIYZS
CWVT BUBA NSGR MUPO LDNS
各単語に含まれる行を印刷しようとしています。同じ文字が2つ以上ある必要があります。、grepを使用すると、command
最も長い行に8単語が含まれます。こうすれば解決できると思いましたが、方法が間違っているようです。
grep '^.*\([A-Z]\)[^ ]*\1[^ ]* [^ ]*\([A-Z]\)[^ ]*\2[^ ]* [^ ]*\([A-Z]\)[^ ]*\3[^ ]* [^ ]*\([A-Z]\)[^ ]*\4[^ ]* [^ ]*\([A-Z]\)[^ ]*\5[^ ]* [^ ]*\([A-Z]\)[^ ]*\6[^ ]* [^ ]*\([A-Z]\)[^ ]*\7[^ ]* [^ ]*\([A-Z]\)[^ ]*\8[^ ]*$/| .... for 7 words | for 6 ...
期待される出力
LTCYMM SVNNDA DTVEV QLOPGO CUPUR
KKPQBP BKDKRU ZTPDPL ZRLUEL HRZZKO KXSKCU YZQTBT RISNKS
答え1
そしてperl
:
$ perl -ne 'print unless grep {!/(.).*\1/} /\S+/g' file
LTCYMM SVNNDA DTVEV QLOPGO CUPUR
KKPQBP BKDKRU ZTPDPL ZRLUEL HRZZKO KXSKCU YZQTBT RISNKS
または、grep
Perl と同様の正規表現をサポートする実装を使用します。
$ grep -Pve '(?<!\S)(?!\S*(\S)\S*\1)\S' file
LTCYMM SVNNDA DTVEV QLOPGO CUPUR
KKPQBP BKDKRU ZTPDPL ZRLUEL HRZZKO KXSKCU YZQTBT RISNKS
印刷された行いいえ( -v
)\S
には、空白以外の文字 ( ) が前に来ず(?<!\S)
(または IOW は空白で区切られた単語の先頭である)、次の空白ではない文字シーケンスの先頭ではない(空白ではない文字)が含まれています。 ((?!\S*(\S)\S*\1)
)が繰り返されます。したがって、perl
上記のアプローチと本質的に似ています(あまり明確ではありません)。
また、空白行も印刷することに注意してください(繰り返し文字がない単語は含まれていないため)。必要でない場合は除外できます。これは簡単です(例:-e '^\s*$'
そこに追加grep
)。
答え2
すべてのUnixシステムのすべてのシェルでawkを使用してください。
awk '{
for ( fldNr=1; fldNr<=NF; fldNr++ ) {
numChars = length($fldNr)
numUnq = 0
split("",seen) # you could use delete(seen) here in most awks
for ( charNr=1; charNr<=numChars; charNr++ ) {
if ( !seen[substr($fldNr,charNr,1)]++ ) {
numUnq++
}
}
if ( numUnq == numChars ) {
next
}
}
print
}' file
LTCYMM SVNNDA DTVEV QLOPGO CUPUR
KKPQBP BKDKRU ZTPDPL ZRLUEL HRZZKO KXSKCU YZQTBT RISNKS
答え3
perl
モジュールall
のメソッドと一緒に使用すると、必要なList::Util
行(1つ以上の繰り返し文字を含むすべての単語)を検出できます。
perl -MList::Util=all -lane '
print if all { /(.).*\1/ } @F;
' file
GnU sed
すべての必須フィールドが行の先頭から最後まで拡張されていることを確認したら、を使用して必要な行を選択できます。
$ sed -En '/^\s*(\S*(\S)\S*\2\S*(\s+|$))+$/p' file
別のアプローチsed
は、空白以外の文字を段階的に実行して重複文字を確認し、空白以外の文字実行で重複が見つからない場合はパターンスペースを印刷しないことです。
sed -Ee 'h
:loop
s/^\s+|\s+$//g
s/\S+/&\n/
/(\S).*\1.*\n/!d
s/^[^\n]*\n//
/./bloop
g
' file
awkを活用し、各単語と単語内の各文字を繰り返します。単語を文字単位で分割して、2つ以上に分割されていることを確認します。 =>その単語でdupが検出されます。同様に、検出された重複数がフィールド数=>印刷に適した行と等しい場合、現在の行の終わりです。
awk '
{
for (p=i=1+(w=0); i<=NF; i++) {
while (p <= length($i)) {
c = substr($i,p++,1)
if (split($i,a,c) > 2) {
w += p = 1
break
}
}
}
}
w==NF
' file
答え4
純粋なBashのもう一つの解決策は次のとおりです。 no perl
、no grep
、no awk
。
#!/bin/bash
set -euo pipefail
containssametwice() {
local -Ai chars=()
local -i i
for ((i = 0; i < ${#1}; ++i)); do
((++chars["${1:i:1}"] < 2)) || return 0
done
return 1
}
while IFS= read -r line; do
read -ra words <<< "$line"
for word in "${words[@]}"; do
containssametwice "$word" || continue 2
done
printf '%s\n' "$line"
done