5

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

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

$string = 'setIfUnmodifiedSince';
echo splitAtUpperCase($string);

输出为“如果未修改则设置”

但我需要一些修改:

  • 当这些字符存在于 string: 中时,该代码片段不处理这些情况ÇÖĞŞÜİ。我不想音译字符。然后我失去了词的意义。我需要使用一些 UTF 字符。该代码使“HereÇonThen”变为“HereÇon Then”
  • 我也不想拆分大写缩写。如果单词是“IKnowYouWillComeASAPHere”,我需要将其转换为“I Know You Will Come ASAP Here”
  • 如果所有字母都是大写,则不要爆炸。就像“不要来这里”
  • 也分解数值。“2013 年结束前”到“2013 年结束前”
  • 如果第一个字符是哈希键 (#),则展开。

案例和预期结果

  1. "comeHEREtomorrow" => "明天来这里"
  2. "KissYouTODAY" => "今天吻你"
  3. "comeÜndeHere" => "来ÜndeHere"
  4. “从不说” => “从不说”
  5. "2013willCome" => "2013 即将到来"
  6. "2013 年结束前" => "2013 年结束前"
  7. “我知道” => “我知道”
  8. "#whatiknow" => "#whatiknow"

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

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

4

4 回答 4

2

/([[:lower:][:digit:]])?([[:upper:]]+)/u应该这样做。

这里/u 用于 Unicode 字符。并且([[:upper:]]+)用于大写字母的序列。

笔记。字母的大小写取决于您使用的字符集。

于 2013-01-08T11:31:35.220 回答
2

一些注意事项:

  • 使用Unicode 属性搜索大写和小写字母(甚至是标题大小写字母 f.ex. Dž Lj Nj Dz
  • comeHEREtomorrow&IKnowThat不能使用一种方法,除非您使用一些字典来查找确切的单词。

    因为如果你想翻译comeHEREtomorrowcome HERE tomorrow, IKnowThatwill be IK now That( 甚至IK now T hat);

    如果你想翻译IKnowThatI Know That,comeHEREtomorrow将是come H E R E tomorrow

我的解决方案:http: //ideone.com/oALyTo(不包括非字母和非数字字符)

于 2013-04-10T17:59:55.093 回答
1

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

我采取了稍微不同的方法。我没有尝试为单词之间的位置编写一个正则表达式,而是编写了一个正则表达式,它查找显然是一个单词的所有内容,然后内爆。

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

正如你所看到的,这就是我决定作为一个词的资格:

^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 #

它并不完美 - 仍然有很多断点。你可以继续完善这些词定义,但坦率地说,总会有你无法捕捉到的边缘情况。然后你慢慢地扩展这个正则表达式,直到它完全无法管理。您可以尝试使用字典,但最终也会失败。你怎么处理“旋风”?还是“伊坦”?是“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]);
}

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

 convert("Icons") = "Icons"
 convert("WellIKnowThat") == "Well I Know That"
 convert("ITan") == "I Tan"
 convert("whirlwind") == "whirlwind"

我认为这和今天的表现差不多。最后一组按优先顺序排列的“词定义”是:

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

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

于 2013-04-12T23:13:11.823 回答
0

你需要 Unicode 正则表达式: \p{Lu} for upercase\p{Li} for lowercase

因此,您的用法将如下所示: /([\p{Ll}0-9])?([\p{Lu}])/

于 2013-04-12T10:45:42.507 回答