【问题标题】:Split text into words problem PHP, complicated problem将文本拆分为单词问题 PHP,复杂问题
【发布时间】:2009-10-21 12:56:09
【问题描述】:

我正在尝试将文本拆分为单词:

$delimiterList = array(" ", ".", "-", ",", ";", "_", ":",
           "!", "?", "/", "(", ")", "[", "]", "{", "}", "<", ">", "\r", "\n",
           '"');
$words = mb_split($delimiterList, $string);

这对字符串很有效,但在某些情况下我不得不处理数字。

例如如果我有文字“看看这个。我的分数是 3.14,我很高兴。”。 现在数组是

[0]=>Look,
[1]=>at,
[2]=>this,
[3]=>My,
[4]=>score,
[5]=>is,
[6]=>3,
[7]=>14,
[8]=>and, ....

然后 3.14 也分为 3 和 14,这在我的情况下不应该发生。 我的意思是点应该划分两个字符串而不是两个数字。 应该是这样的:

[0]=>Look,
[1]=>at,
[2]=>this,
[3]=>My,
[4]=>score,
[5]=>is,
[6]=>3.14,
[7]=>and, ....

但我不知道如何避免这种情况!

有人知道如何解决这个问题吗?

谢谢, 花岗岩

【问题讨论】:

标签: php split


【解决方案1】:

或者使用正则表达式:)

<?php
$str = "Look at this.My score is 3.14, and I am happy about it.";

// alternative to handle Marko's example (updated)
// /([\s_;?!\/\(\)\[\]{}<>\r\n"]|\.$|(?<=\D)[:,.\-]|[:,.\-](?=\D))/

var_dump(preg_split('/([\s\-_,:;?!\/\(\)\[\]{}<>\r\n"]|(?<!\d)\.(?!\d))/',
                    $str, null, PREG_SPLIT_NO_EMPTY));

array(13) {
  [0]=>
  string(4) "Look"
  [1]=>
  string(2) "at"
  [2]=>
  string(4) "this"
  [3]=>
  string(2) "My"
  [4]=>
  string(5) "score"
  [5]=>
  string(2) "is"
  [6]=>
  string(4) "3.14"
  [7]=>
  string(3) "and"
  [8]=>
  string(1) "I"
  [9]=>
  string(2) "am"
  [10]=>
  string(5) "happy"
  [11]=>
  string(5) "about"
  [12]=>
  string(2) "it"
}

【讨论】:

  • 3,14 和 3/14 怎么样?它分裂了。
  • 评论过的效果很好我的意思是 /([\s_;?!\/()[]{}\r\n"]|\.$|[:,.\ -](?=\D)|[:,.\-](?=\D))/. 非常非常非常感谢 ptomli!
  • 如果您像我一样在处理 UTF-8 字符串,请在最后一个 '/' 之后添加一个 'u'
  • 使用/([\s\-_,:;?!\/\(\)\[\]{}&lt;&gt;\r\n="]|\.(?!\d))|(?&lt;!\d)\./5 视为.55. 中的单词,同时仍匹配3.14 等有效浮点数。
【解决方案2】:

看看strtok。它允许您动态更改解析标记,因此您可以在 while 循环中手动拆分字符串,将每个拆分的单词推入一个数组。

【讨论】:

  • 谢谢杰夫。多亏了你,我几乎得到了解决方案,但我有一个小问题。我有一个分隔符列表,无法知道哪个分隔符完全匹配。因为现在我可以检查两个连续的标记,如果它们是数字,我可以加入它们,但我需要知道它们中间是什么。
  • +1 .. 我讨厌称 strtok() 是最可靠的赌注,但在他的情况下,它适用。
  • Granit:我不知道。
【解决方案3】:

我的第一个想法是preg_match_all('/\w+/', $string, $matches);,但这与您得到的结果相似。问题是由点分隔的数字非常模糊。它可以同时表示小数点和句尾,因此我们需要一种方法来更改字符串以消除双重含义。

例如,在这句话中,我们希望将几个部分保留为一个单词:"Look at this.My score is 3.14, and I am happy about it. It's not 334,3 and today's not 2009-12-12 11:12:13."

我们首先构建一个搜索->替换字典,将异常编码为不会被拆分的内容:

$encode = array(
    '/(\d+?)\.(\d+?)/' => '\\1DOT\\2',
    '/(\d+?),(\d+?)/' => '\\1COMMA\\2',
    '/(\d+?)-(\d+?)-(\d+?) (\d+?):(\d+?):(\d+?)/' => '\\1DASH\\2DASH\\3SPACE\\4COLON\\5COLON\\6'
);

接下来,我们对异常进行编码:

foreach ($encode as $regex => $repl) {
    $string = preg_replace($regex, $repl, $string);
}

拆分字符串:

preg_match_all('/\w+/', $string, $matches);

并将编码后的单词转换回来:

$decode = array(
    'search' =>  array('DOT', 'COMMA', 'DASH', 'SPACE', 'COLON'),
    'replace' => array('.',   ',',     '-',    ' ',     ':'    )
);
foreach ($matches as $k => $v) {
    $matches[$k] = str_replace($decode['search'], $decode['replace'], $v);
}

$matches 现在包含拆分为单词的原始句子,但有正确的例外。

您可以根据自己的喜好将异常中使用的正则表达式设置为简单或复杂,但总会出现一些歧义,例如两个句子,第一个结尾,下一个以数字开头:@987654328 @

【讨论】:

    【解决方案4】:

    $delimiterList 中使用". ", 而不是".",

    【讨论】:

    • 你不能确定这一点。例如,我应该也可以处理 this.is.a.text。
    • 你什么时候有“this.is.a.text”并且不想像你的问题中提到的那样拆分它???
    猜你喜欢
    • 2016-01-09
    • 2013-05-05
    • 1970-01-01
    • 2019-08-27
    • 1970-01-01
    • 1970-01-01
    • 2010-10-21
    • 1970-01-01
    • 2011-09-21
    相关资源
    最近更新 更多