
我正在嘗試找出解決方案這問題。到目前為止,我解決這個問題的方法如下。
- 將所有字元附加在一起以使其成為一個長字串。
- 完成上述步驟後,刪除所有空格或製表符空格,這樣我們就只剩下一個大字串了。
我能夠使用以下命令建立上述步驟。
column -s '\t' inputfile | tr -d '[:space:]'
所以對於這樣的輸入文件,
1 0 0 0 0 0
0 1 1 1 0 0
應用上述命令後,我的值如下:
100000011100
現在,在這個大字串中,我嘗試應用以下方法。
提取每 6個字元(如原始 OP 所需),並將其附加到數組元素直到字串末尾。
所以基本上,透過上述步驟,我嘗試將數組元素創建為,
10
(第1和第 7個字元)、01
(第 2和第 8個字元)、01
(第 3和第 9個字元)、01
(第 4和第 10個字元)、00
(第 5和第 11個字元)、00
(第6和 12 個字元)第一個字元)。
所以我的問題是,如何提取每 n 個字符,以便將它們添加到數組中以進一步進行? (在本例中,n=6)。
答案1
兩條線
這是bash
一個產生bash
數組的純解:
s="100000011100"
array=($(
for ((i=0; i<${#s}-6; i++))
do
echo "${s:$i:1}${s:$((i+6)):1}"
done
))
echo "${array[@]}"
這會產生與問題中所示相同的輸出:
10 01 01 01 00 00
這裡的關鍵要素是 bash 的使用子字串擴充。 Bash 允許從變數中提取子字串,例如parameter
via ${parameter:offset:length}
。在我們的例子中,偏移量由循環變數決定i
,長度始終為1
。
任意數量線路的通用解決方案
例如,假設我們的原始字串有 18 個字符,我們要提取 i 從 0 到 5 的第 i 個、第 i+6 個和第 i+12 個字符。
s="100000011100234567"
array=($(
for ((i=0; i<6; i++))
do
new=${s:$i:1}
for ((j=i+6; j<${#s}; j=j+6))
do
new="$new${s:$j:1}"
done
echo "$new"
done
))
echo "${array[@]}"
這會產生輸出:
102 013 014 015 006 007
相同的程式碼可以擴展到任意數量的 6 字元行。例如,如果s
有三行(18 個字元):
s="100000011100234567abcdef"
然後,輸出變成:
102a 013b 014c 015d 006e 007f
答案2
使用perl
:
$ echo 100000011100 | perl -nle '
for ($i = 0; $i < length()/2; $i++) {
print substr($_,$i,1), substr($_,$i+6,1);
}
'
10
01
01
01
00
00
它適用於兩條線。如果您想處理任意行,您應該直接處理行,而不是建立大字串。透過此輸入:
1 0 0 0 0 0
0 1 1 1 0 0
0 0 0 0 0 0
嘗試:
$ perl -anle '
for ($i = 0; $i <= $#F; $i++) {
push @{$h{$i}}, $F[$i];
}
END {
print @{$h{$_}} for keys %h;
}
' file
000
010
000
100
010
010
答案3
作為 shell 解決方案,getopts
可能是最簡單的。問題在於getopts
,它是 POSIX 指定的,可以完全按照您的要求進行操作 - 在 shell 循環中處理位元組流。我知道這聽起來很奇怪,因為如果你在我學到這一點之前像我一樣,你可能會想,好吧,天啊,我以為它應該處理命令列開關。這是事實,但第一件事也是。考慮:
-thisisonelongstringconsistingofseparatecommandlineswitches
是的,getopts
必須處理這個問題。它必須在循環中逐個字符地拆分該字符,然後將 shell 變量$OPTARG
或您通過名稱指定的另一個變量中的每個字符返回給您,這一切都取決於您調用它時獲得的具體程度。更重要的是,它必須傳回 shell 變數中的錯誤儲存其進度當它在 shell 變數中執行時,$OPTIND
它可以從停止處繼續如果你能以某種方式解決它。它必須在不呼叫任何子 shell 的情況下完成整個工作。
假設我們有:
arg=$(seq -s '' 1000); set --
while getopts :0123456789 v -"${arg}"
do [ "$((i=$i+1<6?$i+1:0))" -gt 0 ] ||
set "$@" "$v"
done
嗯......我想知道它是否有效?
echo "$((${#arg}/6))" "$#"
482 482
那很好...
eval '
printf %.1s\\n "${arg#'"$(printf %0$((124*6-1))d | tr 0 \?)"'}" "${124}"'
4
4
因此,如您所見,該getopts
命令為字串中的每六個位元組完全設定了數組。它不一定是這樣的數字 - 甚至也不一定是 shell 安全字元 - 而且您甚至不需要像我上面那樣指定目標字元01234565789
。我已經在很多 shell 中反覆測試過,它們都可以正常工作。有一些怪癖 -bash
如果第一個字符是空白字符,則會丟棄它 -dash
接受:
冒號作為指定參數,即使它是唯一 POSIX 明確禁止的。但這都不重要,因為即使它回傳錯誤,getopts
仍然會存入當前 opt char 的值$OPTARG
(由分配給您指定的 opt 變數的 ? 表示)否則明確取消設置,$OPTARG
除非您聲明選項應該有參數。空白是件好事-它只會丟棄一個領導space,這非常好,因為在處理未知值時,您可以執行以下操作:
getopts : o -" $unknown_value"
....開始循環,而不會有任何第一個字元實際上位於您接受的 args 字串中的危險 - 這將導致立即getopts
將整個內容$OPTARG
插入為參數。
這是另一個例子:
OPTIND=1
while getopts : o -" $(dd if=/dev/urandom bs=16 count=1 2>/dev/null)"
do printf '\\%04o' "'$OPTARG"; done
\0040\0150\0071\0365\0320\0070\0161\0064\0274\0115\0012\0215\0222\0271\0146\0057\0166
我$OPTIND=1
在第一行設定是因為我剛剛使用過getopts
,並且在您重置它之前,它期望下一次調用從它停止的地方繼續 -"${arg2}"
換句話說,它想要。但我不想付出,而且我現在正在做另一件事,所以我透過重置來讓它知道$OPTIND
什麼時候可以開始。
在這個中我使用了zsh
- 它不會對前導空格提出異議 - 因此第一個字元是八進制 40 - 空格字元。不過,我通常不會getopts
以這種方式使用 - 我通常用它來避免對每個位元組執行 a 操作write()
,並將其輸出(來自變數)分配給另一個 shell 變量,就像我上面所做的那樣set
。然後,當我準備好時,我可以獲取整個字串,而當我這樣做時,通常會刪除第一個位元組。
答案4
sed
我首先想到的是。
$ echo 1234567890abcdefghijklmnopqrstuvwxyz | sed 's/.\{5\}\(.\)/\1/g'
6bhntz
匹配 5 個字符,捕獲第 6 個字符,然後將其全部替換為捕獲的字符。
然而,如果字串的長度不是 6 的精確倍數,則會出現問題:
$ echo 1234567890abcdefghijklmnopqrstuvwxy | sed 's/.\{5\}\(.\)/\1/g'
6bhntuvwxy
但我們可以透過sed
稍微改變一下來解決這個問題:
$ echo 1234567890abcdefghijklmnopqrstuvwxy | sed 's/.\{1,5\}\(.\{0,1\}\)/\1/g'
6bhnt
由於正規表示式的貪婪本質,可變長度匹配將盡可能匹配,如果沒有剩餘內容可供捕獲,則不會捕獲,並且字元將被刪除。