2017-02-01 70 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