2017-06-23 27 views
9

我目前有两个数组设置,并且我试图检查单词中的最后两个字母,并用其他字符替换它,如果与第一个数组匹配。我现在正在努力做到这一点,但我不知道如何做到这一点,对于不在行尾的单词。检查并替换行尾或空格前的字符

以下是我的数组可能看起来像的一个示例。这些从数据库查询填充。这些字符可以是任何Unicode字符,因此不一定在A-Z或a-z范围内。

$array1 = ['mp', 'tm', 'de', 'HK']; 
$array2 = ['MAP', 'TM', "DECIMAL", '字']; 

我当前的代码如下所示:

$mystring = "samplemp"; 
$last = substr($mystring, -2); 
$newlast = str_replace($array1, $array2, $last); 
if ($last != $newlast){ 
    $mystring = substr($mystr, 0, 2).$newlast; 
} 

我所工作:

所以,我现在有代码看起来在字符串中的最后两个字符。例如,如果最后两个字符是“mp”,则用“MAP”替换它们。所以,如果我的字符串看起来像:

samplemp 

它被正确地改为

sampleMAP 

至此一切正常。

问题

我有正在处理不在一个字符串末尾的字的问题。例如:

samplemp okay de  hellotm 
blatm theHK end 

sampleMAP okay DECIMAL  helloTM 
blaTM the字 end 

我希望能够考虑到所有空白,包括空格,制表符和回车替换。但是,空格必须保持完整并且不能更改。空格必须保留为空格,制表符作为制表符,并且回车符作为回车。

到目前为止,我已经能够弄清楚,我可能需要使用正则表达式使用\s转义字符来解释空白。但是,我无法理解如何将str_replace函数用于数组。有没有办法做到这一点?如果没有,我还应该做些什么才能使其发挥作用?

+0

你缺少一个'$'这里'$ myString的= SUBSTR($ mystr,0,2).newlast;'应该是'$ mystring = substr($ mystr,0,2)。$ newlast;' – ArtisticPhoenix

+0

感谢您的帮助@ArtisticPhoenix,我没有想到提到的一件事是字符不一定是拉丁字符,而是任何Unicode字符。所以,a-z范围将不起作用。我认为你可能会对preg_replace函数有所了解,但我将不得不更多地关注它,试图搜索空白区域。另外,谢谢你指出我缺少的$。我的真实代码中有$,只是在我的示例中错过了它。 – kojow7

+0

您遇到的问题是str_replace,将取代任何出现的字符串。 preg_replace或Regx通常会让您更​​好地控制匹配发生的位置。 – ArtisticPhoenix

回答

4

我会怎么做:

$string = <<<EOD 
samplemp okay de  hellotm 
blatm theHK end 
EOD; 
$array1 = ['mp', 'tm', 'de', 'HK']; 
$array2 = ['MAP', 'TM', "DECIMAL", '字']; 

$hash = array_combine($array1, $array2); 
foreach($hash as $k => $v) { 
    $string = preg_replace_callback('/'.preg_quote($k).'(?=\s|$)/u', function($m) use($v) { 
     return $v; 
    }, 
    $string 
    ); 
} 
echo $string,"\n"; 

(?=\s|$)是在先行是确保我们有什么样的空间(即空格,制表符,回车,换行,...)或搜索后字符串的结尾ed密钥。有了这个,我们保持白色空间不变。

/u是unicode标志。

输出:

sampleMAP okay DECIMAL  helloTM 
blaTM the字 end 
+0

谢谢你和这个向前看的解释。我之前没有听说过预测,只是意识到它们对于其他情况会有多大用处!我还修改了我的原始代码,现在它使用PDO :: FETCH_KEY_PAIR从数据库中提取数据,这在我之前没有听说过。所以,应该希望使事情快一点,而不是使用array_combine。 – kojow7

+0

您的方法与Josh H提到的方法相比如何? – kojow7

+0

@ kojow7:我的答案是照着任何类型的空格('\ s')或单词后面的结尾(''''),正如你所要求的那样。乔希的回答是照顾一个字的边界。 – Toto

1

你可以使用正则表达式来做到这一点。

首先转换您的模式,以正则表达式和追加 '\ B' 到你的模式,这意味着字边界(空格,制表,EOL ...):

foreach($array1 as $k => $v) { 
    $array1[$k] = '/'.$v.'\\b/'; 
} 

然后用了preg_replace替换:

$result = preg_replace($array1, $array2, "samplemp okay hellotm"); 
+0

这将在所有单词的末尾替换它,而不仅仅是字符串的最后一个单词。 – Barmar

+0

@Barmar我想要替换字符串中所有单词的最后一个字符。 – kojow7

+0

@ kojow7您从发布的代码中看不清楚,因为您从不将“$ mystring”分成单独的单词。 – Barmar

2

使用正向表达式,该向前表达式匹配字符串末尾的任何空白序列。

$array1 = ['/mp(?=\s*$)/', 'tm(?=\s*$)/', 'de(?=\s*$)/']; 
$array2 = ['MAP', 'TM', "DECIMAL"]; 

$newlast = preg_replace($array1, $array2, $last); 
+0

由于数组正在从数据库填充并可能包含超过一百个项目,您是否建议我循环$ array1并将'/'和'(?= \ s * $)/'连接到每个项目数组? – kojow7

+0

是的,这就是如何动态地做到这一点。 – Barmar

2

未经测试,你可以做这样的事情

$array2 = ['mp' => 'MAP', 'tm' => 'TM', 'de' => "DECIMAL"]; 

$mystring = "samplemp"; 
$patt = '/('.implode('|',array_keys($array2)) .')\b/'; 

$newlast = preg_replace_callback($patt , function($m) use ($array2){ 
    return $array2[$m[1]]; 
}, $mystring); 

echo "\n$newlast"; 

使用preg_replace_callback你能避免通过输入数组,而是循环虽然比赛,这应该提供一些性能小幅上升循环,眼见在大多数情况下,会有更多的可能性(输入),然后是实际匹配。

这个正则表达式的作品出来是这样的:

/(mp|tm|de)\b/ 

所以,这将捕获mptmde而只用一个字末突破\b,为的结束字符串或单词的结尾,因此它不会匹配dende例如。

回调部分是非常直接的,每当输入字符串匹配时,回调被触发,并且该匹配作为第一个参数传递给该函数。比赛的格式就像preg_match的作品。然后,无论您返回什么作为替换字符串。这只是访问数组中key =>值对的简单方法。

use在闭包中只是一个范围解析运算符,它允许您传递通常不在闭包范围之外的变量。 '

这样做的真正好处是,您不必为模式使用循环来准备数组,只需对它进行内部处理即可。此外,它在匹配上循环,而不是在输入上循环。大多数其他答案会做一个循环来准备模式,然后再循环模式。 “循环赛是不可避免的”,我说松散循环只是意味着重复的操作。

在任何情况下,你可以在这里

https://regex101.com/r/AYw111/1

+0

谢谢你的回答。我很难完全理解你的代码,因为我不太熟悉回调。然而,没有进一步的解释,我不明白它是如何解释和保留空白的。 – kojow7

+0

它没有帐户或保留空白,它忽略它。 '\ b'是一个单词中断或单词的结尾,所以它是匹配的,数组键'|'pipe是一个或者,在一个单词的结尾,并用该单词的数组值替换它。 – ArtisticPhoenix

+0

preg_replace_callback,每次与匹配'$ m'匹配时触发回调,'use'部分只允许'$ array'变量的作用域。 – ArtisticPhoenix

1

测试至REGx您可以分割字符串到数组,然后检查特定的词为您更换。试试这个:

$array1 = ['mp', 'tm', 'de', 'HK']; 
$array2 = ['MAP', 'TM', "DECIMAL", '字']; 

$mystring = "samplemp \t okay hellotm"; 
preg_match_all('/\s+/', $mystring,$space_array); 
$space_array = isset($space_array[0])?$space_array[0]:$space_array; 
$test_array = preg_split('/\s+/', $mystring); 
$change_array= array(); 
$new_str = ""; 
foreach ($test_array as $key => $value) {   
    $last = substr($value, -2); 
    $newlast = str_replace($array1, $array2, $last); 
    if ($last != $newlast){ 
     $value = substr($value, 0, strlen($value)-2).$newlast; 
    } 
    $value .= isset($space_array[$key])?$space_array[$key]:""; 
    $change_array[] = $value;  
} 
var_dump(implode("", $change_array)); 
+0

感谢您的回答,但是,作为我请求的一部分,它必须能够考虑所有类型的空白,而不仅仅是空格。 – kojow7

+0

@ kojow7我编辑了我所有类型的空间的代码。现在检查它。 –

1

这里有一个快速的功能,我敲在一起,应该做你需要的。它分割字符串,然后查找array1中的最后2个字母。如果它发现它,它将使用array2中的结束字母替换。如果它到达循环的结尾并且没有返回,则返回原始字符串。

<?php 

function replaceString($string) 
{ 
    $array1 = ['mp', 'tm', 'de']; 
    $array2 = ['MAP', 'TM', "DECIMAL"]; 
    $first = substr($string, 0, -2); 
    $last = substr($string, -2); 
    $split = [ 
     'start' => $first, 
     'end' => $last, 
    ]; 
    foreach ($array1 as $key => $val) { 
     if ($val == $split['end']) { 
      $word = $split['start'].$array2[$key]; 
      return $word; 
     } 
    } 
    return $string; 
} 


echo replaceString("samplemp")."\n"; 
echo replaceString("okay")."\n"; 
echo replaceString("hellotm")."\n"; 

sampleMAP 好吗 helloTM

活生生的例子这里https://3v4l.org/fJCIY

+0

你似乎在这里手动分割字符串。我需要保持原始空白完好的东西。 – kojow7

1

多去一些其他的答案已经在这里稍微简单:

$mystring = <<<EOD 
samplemp okay MADE de  hellotm 
blatm theHK end 
EOD; 
$array1 = ['mp', 'tm', 'de', 'HK']; 
$array2 = ['MAP', 'TM', "DECIMAL", '字']; 
foreach($array1 as $key=>$v){ 
    $mystring = preg_replace("/".preg_quote($v)."\b/u", $array2[$key], $mystring); 
} 
相关问题