2019-11-08

壞字符規則

壞字符規則 - 移動格數:

在$Key裡,尋找和壞字符相同的字。
移動格數:
    有找到:壞字符位置 - 找到的位置
    沒找到:壞字符位置 - (-1)
比對方向 
01234
QQQQBCABC
    
BCAB
01234
            壞字符:A
            壞字符位置:4
        
            在後續移動過程中,仍有機會和「壞字符A」對齊的字:
                位置 4 左邊的字
                $Key[0]到 $Key[3]

            和壞字符相同的字的位置:2

            移動格數:壞字符位置 - 找到的位置
                    4 - 2 = 2

QQQQBCABC
    
 BCAB
$Key移動 

QQQQBCABC
    
  BCAB

          找到A對齊,移動2格

比對方向 
01234
QQQQBCABC
    
BCAB
01234
            壞字符:B
            壞字符位置:4
        
            在後續移動過程中,仍有機會和「壞字符B」對齊的字:
                位置 4 左邊的字
                $Key[0]到 $Key[3]
            
            和壞字符相同的字的位置:3

            移動格數:壞字符位置 - 找到的位置
                    4 - 3 = 1

QQQQBCABC
    
 BCAB
         找到B對齊,移動1格
         $Key裡 有 2 個 B
         找距離「壞字符」最近的那個
比對方向 
01234
QQBCBBCABC
  
BCBC
01234
            壞字符:B
            壞字符位置:2
        
            在後續移動過程中,仍有機會和「壞字符B」對齊的字:
                位置 2 左邊的字
                $Key[0]到 $Key[1]
            
            和壞字符相同的字的位置:0

            移動格數:壞字符位置 - 找到的位置
                    2 - 0 = 2

QQBCBBCABC
  
 BCBC
$Key移動 

QQBCBBCABC
  
  BCBC
         找到B對齊,移動2格
         有 2 個B,$Key[0] 和 $Key[3]
         只找$Key移動時,會經過壞字符的那個
比對方向 
01234
QQQQBCABC
    
BCAB
01234
            壞字符:M
            壞字符位置:4
        
            在後續移動過程中,仍有機會和「壞字符M」對齊的字:
                位置 4 左邊的字
                $Key[0]到 $Key[3]
            
            和壞字符相同的字的位置:沒找到

            移動格數:壞字符位置 - 沒找到
                    4 - (-1) = 5

QQQQBCABC
    
 BCAB
$Key移動 

QQQQBCABC
    
  BCAB
$Key移動 

QQQQBCABC
    
   BCAB
$Key移動 

QQQQBCABC
    
    BCAB
$Key移動 

QQQQBCABC
    
     BCAB
           找不到 M,移動5格
比對方向 
01234
QABCBCABC
 
ABC
01234
            壞字符:A
            壞字符位置:1
        
            在後續移動過程中,仍有機會和「壞字符A」對齊的字:
                位置 1 左邊的字
                $Key[0]
            
            和壞字符相同的字的位置:沒找到

            移動格數:壞字符位置 - 找到的位置
                    1 - (-1) = 2

QABCBCABC
 
 ABC
$Key移動 ABCBCABC
 
  ABC
          找不到 A,移動2格


$Key移動方向、比對方向 - 必須不同

01234
QQQQBCABC

CABC
            $Key移動方向 
            比對方向 

            壞字符:A
            壞字符位置:0

            之後移動時,$Key的其他字不會經過壞字符A

     01234
BCABCQQQQ
     
     CABC
                    $Key移動方向 
                    比對方向 

                    壞字符:A
                    壞字符位置:0

        之後移動時,$Key的其他字經過壞字符A,有機會對齊
     01234
BCABCQQQQ
         
     BCAB
                    $Key移動方向 
                    比對方向 

                    壞字符:A
                    壞字符位置:4

            之後移動時,$Key的其他字不會經過壞字符A
關於「移動」:
    $Key在程式碼中,沒有移動
    移動的是$base


模擬製表 $Bc

「壞字符」、「壞字符的位置」是未知的
模擬「各種比對失敗位置」、「各種壞字符」要移動幾格

$Bc[比對失敗位置 ][可能的壞字符]
為表達方便,「可能的壞字符」用string來表示
但實際上,「可能的壞字符」是 int
比對方向 
01234
QQQQ BCABC
    
BCAB
01234


$Key[0] 到 $Key[3]之間的字
找距離「壞字符」最近的那個
$Bc[4]['B'] = 4 - 3
$Bc[4]['A'] = 4 - 2
$Bc[4]['C'] = 4 - 1     #不會用到。不過,簡化版會用到

其他字
$Bc[4]['D'] = 4 - (-1)
$Bc[4]['E'] = 4 - (-1)
$Bc[4]['F'] = 4 - (-1)
$Bc[4]['G'] = 4 - (-1)
...
$Bc[4]['Z'] = 4 - (-1)
比對方向 
01234
QQQ CBBCABC
   
BCAC
01234

$Key[0] 到 $Key[2]之間的字
找距離「壞字符」最近的那個
$Bc[3]['A'] = 3 - 2
$Bc[3]['C'] = 3 - 1
$Bc[3]['B'] = 3 - 0     #不會用到

其他字
$Bc[3]['D'] = 3 - (-1)
$Bc[3]['E'] = 3 - (-1)
$Bc[3]['F'] = 3 - (-1)
$Bc[3]['G'] = 3 - (-1)
...
$Bc[3]['Z'] = 3 - (-1)

比對方向 
01234
QQ BCBBCABC
  
BCBC
01234

$Key[0] 到 $Key[1]之間的字
找距離「壞字符」最近的那個
$Bc[2]['C'] = 2 - 1
$Bc[2]['B'] = 2 - 0

其他字
$Bc[2]['A'] = 2 - (-1)     #不會用到
$Bc[2]['D'] = 2 - (-1)
$Bc[2]['E'] = 2 - (-1)
$Bc[2]['F'] = 2 - (-1)
$Bc[2]['G'] = 2 - (-1)
...
$Bc[2]['Z'] = 2 - (-1)
        


開始製表 $Bc

#設定 $Bc 時,只需要用到 $Key
$Key = 'BCABC'

#設定預設值
#假設$Text $Key裡面只有英文、數字
#陣列的大小為 256

# $B4是一個陣列
# $B4[0]  到 $B4[255] 的值都是 5
$B4 = @( 4 - (-1) ) * 256

# $B3是一個陣列
# $B3[0]  到 $B3[255] 的值都是 4
$B3 = @( 3 - (-1) ) * 256

$B2 = @( 2 - (-1) ) * 256       #都是 3
$B1 = @( 1 - (-1) ) * 256       #都是 2
$B0 = @( 0 - (-1) ) * 256       #都是 1

# $Bc是一個陣列,內含$B0 $B1 $B2 $B3 $B4
$Bc = $B0, $B1, $B2, $B3, $B4

# 設定 $Bc[4]:第一版

    #從$Key[3] 到 $Key[0]  是可能的壞字符
for ( $i = 3 ; $i -ge 0 ; $i-- ){
    [int]$badChar = $Key[$i]
    $Bc[4][ $badChar ] = 4 - $i
}

# 設定 $Bc[4]:第二版
# 當相同字符有兩個以上時,第一次遇到時,才設值

for ( $i = 3 ; $i -ge 0 ; $i-- ){
    [int]$badChar = $Key[$i]
        #如果是預設值 5 ,表示是第一次遇到
    if ($Bc[4][ $badChar ] -eq 5){
        $Bc[4][ $badChar ] = 4 - $i
    }
    
}

# 設定 $Bc[4]:第三版
#設值順序改成:從 $Key[0] 到 $Key[3]
#這樣可以不用 if 判斷了
for ( $i = 0 ; $i -le 3 ; $i++ ){ # 0 到 3
    [int]$badChar = $Key[$i]
    $Bc[4][ $badChar ] = 4 - $i
}

#===== 它們的算法很像 =====

#設定 $Bc[4]
for ( $i = 0 ; $i -le 3 ; $i++ ){ # 0 到 3
    [int]$badChar = $Key[$i]
    $Bc[4][ $badChar ] = 4 - $i  # 4 - $i
}

#設定 $Bc[3]
for ( $i = 0 ; $i -le 2 ; $i++ ){ # 0 到 2
    [int]$badChar = $Key[$i]
    $Bc[3][ $badChar ] = 3 - $i  # 3 - $i
}

#設定 $B[2]
for ( $i = 0 ; $i -le 1 ; $i++ ){ # 0 到 1
    [int]$badChar = $Key[$i]
    $Bc[2][ $badChar ] = 2 - $i  # 2 - $i
}

#===== 原來的版本 =======
$Bc = $B0, $B1, $B2, $B3, $B4

#在 4 比對失敗 移動格數
$Bc[4][ [int][char]$badChar]

#在 3 比對失敗 移動格數
$Bc[3][ [int][char]$badChar]

#===== 簡化的版本 =======
#不用設定 $B0, $B1, $B2, $B3 了
$Bc = $B4

#在 4 比對失敗 移動格數
$Bc[ [int][char]$badChar] - (4 - 4)

#在 3 比對失敗 移動格數
$Bc[ [int][char]$badChar] - (4 - 3)

#在 2 比對失敗 移動格數
$Bc[ [int][char]$badChar] - (4 - 2)

#===== $Bc 簡化版 ======
$Text = 'QQQQQBCABC'
$Key = 'BCABC'

# 製表 $Bc
# $Bc是一個陣列,長度64KB,每個單位的值都是5
$Bc = @( 5 ) * 64KB

for ( $i = 0 ; $i -le 3 ; $i++ ){ # 0 到 3
    [int]$badChar = $Key[$i]
    $Bc[ $badChar ] = 4 - $i
}

$base = 0
while ($base -lt 6){

    # 方向相反
    for ($i = 4 ; $i -ge 0 ; $i--){
        if ( $Key[$i]  -ne  $Text[$base + $i] ){ break }
    }

    if ($i -eq -1 ){ "$Key$base" ; break }
    
    # 移動幾格 
    [int]$badChar = $Text[$base + $i]
    $B_move = $Bc[ $badChar ] - (4 - $i)
    #有時 $B_move 值 會是負的。這時需要靠 $Gs[$i]

    #$Gs還沒設定,執行此程式碼會出錯
    if ( $B_move  -gt $Gs[$i] ){
        $base += $B_move
    }else{
        $base += $Gs[$i]
    }
}

if ($base -ge 6) { "沒找到"}

沒有留言:

張貼留言