2017-02-01 75 views
3

我正在尋找將一行開頭的4個空格替換爲標籤,但沒有任何進一步的文本存在。使用標籤替換空間縮進

爲了便於閱讀,我的初始正則表達式爲/ {4}+//[ ]{4}+/,但顯然任何帶有四個空格的實例都將被替換。

$string = '  this is some text --> <-- are these tabs or spaces?'; 
$string .= "\n and this is another line singly indented"; 
// I wrote 4 spaces, a tab, then 4 spaces here but unfortunately it will not display 
$string .= "\n \t and this is third line with tabs and spaces"; 

$pattern = '/[ ]{4}+/'; 
$replace = "\t"; 

$new_str = preg_replace($pattern , $replace , $string); 

echo '<pre>'. $new_str .'</pre>'; 

這是什麼,我原本使用給出的表達問候的轉換,但一個事實,完美的作品正則表達式的例子是,之間的4個空格----> ---- <被一個標籤取代。我真的很希望壓縮後的文本保持不變。

我最大的努力迄今已(^)線的起點([ ]{4}+)模式(.*?[;\s]*)任何東西直到第一個非空間\s

$pattern = '/^[ ]{4}+.*?[;\s]*/m';

這......幾乎工程,但對於事實上,縮進現在已經失去了,任何人都可以幫助我理解我在這裏失去了什麼?

[編輯]

爲清楚什麼,我試圖做的是改變從空間到標籤的文本縮進的開始,我真的不明白爲什麼這是混亂的人。

要儘可能明確(使用上面的$string值):

First line has 8 spaces at the start, some text with 4 spaces in the middle. 
I am looking for 2 tabs at the start and no change to spaces in the text. 

Second line has 4 spaces at the start. 
I am looking to have only 1 tab at the start of the line. 

Third line has 4 spaces, 1 tab and 4 spaces. 
I am looking to have 3 tabs at the start of the line. 
+0

我可能失去了一些東西。你的問題只有一個標籤更換四個空格,或者是 – Niitaku

+0

嘗試'preg_replace('〜(?:^ | \ G)[] {4}〜m',「\ t」,$ s)',請參閱https://ideone.com/EzjRYC。 –

+0

@WiktorStribiżew這仍然沒有解決第三行中間有一個標籤 – Lucas

回答

0

如果你不是一個正則表達式大師,這將可能使最有意義的你,更容易適應類似用途的情況下(這是不是最有效的代碼,但它是最「可讀」恕我直言):

// replace all regex matches with the result of applying 
// a given anonymous function to a $matches array 
function tabs2spaces($s_with_spaces) { 
    // before anything else, replace existing tabs with 4 spaces 
    // to permit homogenous translation 
    $s_with_spaces = str_replace("\t", ' ', $s_with_spaces); 
    return preg_replace_callback(
     '/^([ ]+)/m', 
     function ($ms) { 
      // $ms[0] - is full match 
      // $ms[1] - is first (...) group fron regex 

      // ...here you can add extra logic to handle 
      // leading spaces not multiple of 4 

      return str_repeat("\t", floor(strlen($ms[1])/4)); 
     }, 
     $s_with_spaces 
    ); 
} 

// example (using dots to make spaces visible for explaining) 
$s_with_spaces = <<<EOS 
no indent 
....4 spaces indent 
........8 spaces indent 
EOS; 
$s_with_spaces = str_replace('.', ' '); 
$s_with_tabs = tabs2spaces($s_with_spaces); 

如果你想有一個高性能的,但很難理解或調整的單行代替,註釋中的解決方案從正則表達式上面應該工作:)


P.S.通常preg_replace_callback(和its equivalent in Javascript)是一款結構化文本處理的偉大「瑞士軍刀」。我有,可恥的是,甚至使用它的迷你語言書寫解析器;)

+0

謝謝,不幸的是,這在第三行(顯示2個選項卡,然後是4個空格)也很短 - 我真的希望使用正則表達式,以便它可以繼承到其他語言。 – Lucas

+0

@Lucas你可以簡單地用空格替換所有現有的標籤,然後再進行轉換,以使其在第三行也可以工作(如果你還想避免標籤後面的標籤,你也可以基於蜜蜂正則表達式進行優化)。我更新了我的解決方案,至少在最簡單的情況下解決這個問題。我建議不要使用「monter regexes」:任何時候我在代碼審查中發現它們時,我會要求使用更多代碼(和註釋)+簡單正則表達式進行重寫,或者在可能時或最壞情況下,在它們之間有足夠的註釋的小字符串 - 代碼可讀性高於:) – NeuronQ

0

我會這樣做的方式。

$str = "..."; 
$pattern = "'/^[ ]{4}+/'"; 
$replace = "\t"; 

$multiStr = explode("\n", $str); 
$out = ""; 
foreach ($multiStr as &$line) { 
    $line = str_replace("\t", " ",$line); 
    $out .= preg_replace($pattern , $replace , $line) 
} 

$results = implode("\n", $out); 

請以徹底和直觀的方式徹底重新評估代碼。

正如我不能運行PHP服務器來測試它:(但應該可以幫助您解決了這個問題。

+0

公共PHP服務器,https://3v4l.org/,https://eval.in/。 – chris85