爆炸关于大写或数字字符的UTF8字符串

tra*_*nte 5 php regex string utf-8 preg-replace

作为这个问题,我可以拆分包括大写的字符串,如下所示:

function splitAtUpperCase($string){
    return preg_replace('/([a-z0-9])?([A-Z])/','$1 $2',$string);
}

$string = 'setIfUnmodifiedSince';
echo splitAtUpperCase($string);
Run Code Online (Sandbox Code Playgroud)

输出是"设置如果未修改自"

但我需要一些修改:

  • 当字符串中存在这些字符时,该代码段不处理这些情况:ÇÖ??Ü?.我不想音译这些人物.然后我失去了言语的意义.我需要使用一些UTF字符.该代码使"HereÇonThen"变为"Hereonon Then"
  • 我也不想拆分大写缩写.如果单词是"IKnowYouWillComeASAPHere",我需要将其转换为"我知道你会尽快到来"
  • 如果所有字母都是大写字母,请不要爆炸.喜欢"DONTCOMEHERE"
  • 同时爆炸数值."2013年之前"到"2013年结束前"
  • 如果第一个字符是散列键(#),则爆炸.

案件和预期结果

  1. "comeHEREtomorrow"=>"明天来这里"
  2. "KissYouTODAY"=>"亲吻你今天"
  3. "comeÜndeHere"=>"来Ünde这里"
  4. "NEVERSAYIT"=>"NEVERSAYIT"
  5. "2013willCome"=>"2013将来"
  6. "Before2013ends"=>"2013年结束前"
  7. "IKnowThat"=>"我知道"
  8. "#whatiknow"=>"#whatiknow"

对于这些情况,我使用后续str_replace操作.我寻找一个简短的解决方案,不会为循环检查单词做太多.preg_replace如果可能的话,最好将它作为等等.

编辑:任何人都可以通过改变convert这个PHP小提琴中的函数来尝试他的解决方案:http://ideone.com/9gajZ8

Fra*_*Man 1

好吧,我匹配了你所有的测试用例,但我仍然认为这不是一个好的解决方案。(测试驱动设计中的少数缺陷之一)。

我采取了稍微不同的方法。我没有尝试编写一个正则表达式来描述单词之间的位置应该是什么样子,而是编写了一个正则表达式来查找所有明显是单词的内容,然后内爆。

function convert($keyword) {
   $wResult = preg_match_all('/(^I|[[:upper:]]{2,}|[[:upper:]][[:lower:]]*|[[:lower:]]+|\d+|#)/u', $keyword, $matches);
   return implode(' ',$matches[0]);
}
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,我决定将其限定为一个词:

^I                 A capital I at the beginning of the string.  Break point: Icons.
[[:upper:]]{2,}    Consecutive capitals.  Break Point:  WellIKnowThat
[[:upper:]][[:lower:]]*    A single Capital followed by some lower case letters
[[:lower:]]+       A string of lower case letters
\d+                A string of digits
#                  A literal #
Run Code Online (Sandbox Code Playgroud)

它并不完美——仍然有很多断点。您可以继续完善这些单词定义,但坦率地说,总会有您无法捕获的边缘情况。然后你最终会慢慢地扩展这个正则表达式,直到它完全无法管理。你可以尝试使用字典,但最终也会失败。你用“旋风”做什么?还是“伊坦”?是“IT an”还是“I Tan”?举个例子? 是我尝试发现一些错误之后的结果。它变得如此之大,而想出它所破坏的绳子仍然是微不足道的。这个函数全都是关于学位的——值得花多少时间来教你的算法所有世界语言的所有有趣之处?

编辑:经过一番工作,并决定我可以作为自己的单词分离出来,当且仅当它紧随其后的是一个大写字母和一个小写字母时,我更新了我对答案的尝试。

function convert($keyword, $debug = false) {
   $wResult = preg_match_all('/I(?=[[:upper:]][[:lower:]])|[[:upper:]]{2,}|[[:upper:]][[:lower:]]*|[[:lower:]]+|\d+|#/u', $keyword, $matches);
   if($debug){
       var_dump($matches);
       var_dump($matches[0]);
       var_dump(implode(' ',$matches[0]));
   }
   return implode(' ',$matches[0]);
}
Run Code Online (Sandbox Code Playgroud)

我还添加了一些新的测试用例:

 convert("Icons") = "Icons"
 convert("WellIKnowThat") == "Well I Know That"
 convert("ITan") == "I Tan"
 convert("whirlwind") == "whirlwind"
Run Code Online (Sandbox Code Playgroud)

我认为这与今天的情况差不多。按照优先顺序排列的最终“单词定义”集是:

  1. 大写 I,前提是后面跟着一个大写字母和一个小写字母:I(?=[[:upper:]][[:lower:]])
  2. 两个或多个连续的大写字母:[[:upper:]]{2,}
  3. 一个大写字母,后跟尽可能多的小写字母:[[:upper:]][[:lower:]]*
  4. 一个或多个连续的小写字母:[[:lower:]]+
  5. 一位或多位连续数字:\d+
  6. 英镑符号:#

我添加了另一个单词定义、一个测试用例,并改进了测试 fiddle。新单词定义与 的规则匹配I,但与A- 英语中唯一的另一个单字母单词。