2017-10-21 81 views
0

我正在創建一個單詞替換腳本。我遇到了一個忽略引號之間的字符串的路障,一直沒能找到一個不涉及正則表達式的體面解決方案。沒有正則表達式:行情之間的字符串?

我有一個工作的片斷,通過串並計算出是否與最近的報價在每一個字符的週期是一個打開或關閉引號(無論是單人或雙人),並忽略轉義的引號。問題是,爲了提供100%準確的體驗,每次字符串更改時都必須運行(由於它的工作原理,在單個函數中它可能會改變超過60K次),並且由於字符串長度潛在的代碼需要很長的時間,即使是一個相當短的腳本。

有沒有想出一個字符串是否是打開和關閉引號(單雙)之間的快捷方式?忽略溢出「和」。或者,你有關於如何優化代碼片段以使其運行速度顯着加快的建議?刪除此功能後,該進程幾乎以首選速度運行(即時)

作爲練習,考慮例如$ thisIsAQuote =「這是一個引號」;並且從這一點開始,除了$ thisIsAQuote應該保留其確切的文字外,所有的東西都應該正確地替換。

但這裏的問題:其他的解決方案,我發現將把之間的一切「這是一個報價。」和... $這個 - >格式化[$ I - 1] =「......彷彿它仍然引號之間! 。因爲就這些解決方案而言,「這是一個報價」中的最後一句話。並且if-check中的第一個引號是打開和關閉的引號。另一個明顯的問題是一些字符串包含帶撇號的單詞。撇號不應被視爲單引號,但在我找到的所有解決方案中,它們都是。

換句話說,他們是「不知道」的解決方案。

$quoteClosed = true; 
    $singleQuoteClosed = true; 

    $codeLength = mb_strlen($this->formatted); 
    if ($codeLength == false) 
     return; 

    for ($i = 0; $i < $codeLength; $i++) 
    { 
     if ((!$quoteClosed || !$singleQuoteClosed) && ($this->formatted[$i] == '"' || $this->formatted[$i] == "'")) 
     { 
      if (!$quoteClosed && $this->formatted[$i - 1] != "\\") 
       $quoteClosed = true; 
      else if (!$singleQuoteClosed && $this->formatted[$i - 1] != "\\") 
       $singleQuoteClosed = true; 
     } 
     else if ($this->formatted[$i] == '"' && ($i <= 0 || $this->formatted[$i - 1] != "\\")) 
     { 
      if ($quoteClosed && $singleQuoteClosed) 
       $quoteClosed = false; 
     } 
     else if ($this->formatted[$i] == "'" && ($i <= 0 || $this->formatted[$i - 1] != "\\")) 
     { 
      if ($singleQuoteClosed && $quoteClosed) 
       $singleQuoteClosed = false; 
     } 

     if ($quoteClosed && $singleQuoteClosed) 
      $this->quoted[$i] = 0; 
     else 
      $this->quoted[$i] = 1; 
    } 

如果沒有一種方法,使上述更高效,是有一個非正則表達式的方式來快速替換與子陣列中的所有子在第二陣列,而不在整個字符串中缺少任何?

substr_replace和str_replace函數似乎只是更換整個字符串,這就是爲什麼迭代次數到位的「一些」作品。它循環一個while循環,直到任何strpos認爲字符串不存在爲止(它似乎從來沒有做過......我可能錯誤地使用它),或者循環10K次,以先發生者爲準。

運行上面的代碼片段 - 每一輪將解決速度問題,但這留下了「完全替換」的問題,當然,保持意識到它應該避免替換引號內的任何內容。

for ($a = 0; $a < count($this->keys); $a++) 
    { 
     $escape = 0; 
     if ($a > count($this->keys) - 5) 
      $this->formatted = $this->decodeHTML($this->formatted); 

     while (strpos($this->formatted, $this->keys[$a]) !== false) 
     { 
      $valid = strpos($this->formatted, $this->keys[$a]); 
      if ($valid === false || $this->quoted[$valid] === 1) 
       break; 

      $this->formatted = substr_replace($this->formatted, $this->answers[$a], $valid, mb_strlen($this->keys[$a])); 
      $this->initializeQuoted(); 
      $escape++; 

      if ($escape >= 10000) 
       break; 
     } 

     if ($a > count($this->keys) - 5) 
      $this->formatted = html_entity_decode($this->formatted); 
    } 
    $this->quoted = array(); 
    $this->initializeQuoted(); 
    return $this->formatted; 

'keys'和'answers'是包含各種長度的單詞的數組。 '格式化'是具有改變的信息的新字符串。 'initializeQuoted'是上面的代碼片段。我使用htmlentities和html_entity_decode來幫助擺脫鍵/回答替換空白。

忽略幻數(5S和10K)。

+1

你有沒有想過只是先打電話給該功能?也許這會很好。 –

+0

你是指在while循環之前運行函數嗎?我已經這樣做了,但是它會導致嚴重的錯誤(很多錯過的更改),因爲while循環執行更改,並且在進行單一更改時quote-tracker不再是最新的,更不用說幾個了。自然,每次在while循環後運行函數都有完全相同的問題。 –

+0

_「撇號不應被視爲單引號,但在我找到的所有解決方案中,它們都是。」 - 這可能是由於該要求的複雜性,儘管您只是簡單地將它扔在冷漠的「哦,我也需要這個,但這應該不是什麼大事」。 「如果我沒有記錯的話,那本書的標題是'漢斯最喜歡的詩'。」 - 現在你告訴我你期望弄清楚哪一個是正確的結尾單引號的腳本邏輯?這需要了解_human language_,所以你在這裏接近AI功能。 – CBroe

回答

1

如果我理解正確的話,那麼你可以這樣做:

$replacements = [ 
    "test" => "banana", 
    "Test" => "Banana" 
]; 

$brackets = [[0]]; 
$lastOpenedQuote = null; 



for ($i = 0;$i < strlen($string);$i++) { 

    if ($string[$i] == "\\") { $i++; continue; } //Skip escaped chars 

    if ($string[$i] == $lastOpenedQuote) { 
     $lastOpenedQuote = null; 
     $brackets[count($brackets)-1][] = $i; 
     $brackets[] = [ $i+1 ]; 
    } elseif ($lastOpenedQuote == null && ($string[$i] == "\"" || $string[$i] == "'")) { 
     $lastOpenedQuote = $string[$i]; 
     $brackets[count($brackets)-1][] = $i-1; 
     $brackets[] = [ $i ]; 
    } 
} 
$brackets[count($brackets)-1][] = strlen($string)-1; 

$prev = 0; 
$bits = []; 
foreach ($brackets as $index => $pair) { 
    $bits[$index] = substr($string,$pair[0],$pair[1]-$pair[0]+1); 
    if ($bits[$index][0] != "\"" && $bits[$index][0] != "'") { 
     $bits[$index] = str_replace(array_keys($replacements),array_values($replacements), $bits[$index]); 
    } 
} 

瞧瞧吧:http://sandbox.onlinephpfunctions.com/code/0453cb7941f1dcad636043fceff30dc0965541ee

現在,如果性能仍然是一個問題,記住這個經歷每一串字符1次並且每次都需要進行最少次數的檢查,所以很難將其減少更多。也許你應該修改你的方法,從底部開始,如果你需要更快的東西,比如說。在客戶端逐漸進行一些拆分,而不是在服務器端的整個字符串上進行拆分。

+0

呵呵。我將不得不剖析它,但看着沙箱,看起來像是會起作用。謝謝! –

相關問題