将字符串拆分为字典单词和非字典单词

时间:2015-08-19 03:35:16

标签: javascript regex string algorithm

我想用字典将字符串拆分成一系列单词。

以下功能只给我带字母边界的单词。

function spltToWord(prm){
    var spltedAr = prm.split(/(?=[A-Z][a-z])/);
    return spltedAr.join(" ").trim();
}

我想将文本分成字典/非字典单词。

例如:

Iamno123prisoner - 我不是123囚犯

USAisveryrich - 美国非常富有

Albertgaveme5rupees - Albert给了我5卢比

  

可以找到示例字典Here以供参考。

2 个答案:

答案 0 :(得分:3)

如果字典包含很多单词,那么您需要一个更快的解决方案,而不是一次匹配一个单词与输入文本的子字符串。如果字典中有一万个单词,你必须用这种天真的方法做至少一万个字符比较。

更有效的解决方案是使用trie来存储字典单词。检查单词是否在字典中只需要通过字符串一次。

另一个优点是您可以从文本中的给定位置开始搜索最长匹配。以下代码段演示了此方法,其中包含一个足以处理示例的小字典。在本地运行代码时,可以用自己的字典替换它。

var Global = {
  dictionary: [
    'aa', 'I', 'i', 's',
    'aah', 'am',
    'aahed', 'no',
    'aahing', '123',
    'aahs', 'prisoner',
    'aal', 'USA',
    'aalii', 'is',
    'aaliis', 'very',
    'aals', 'rich',
    'aardvark', 'Albert',
    'aardvarks', 'gave', 'me', '5', 'rupees'
  ]
};

function addToTrie(word) {
  var node = Global.trie;
  for (var pos = 0; pos < word.length; ++pos) {
    var letter = word.charAt(pos);
    if (node[letter] === undefined) {
      node[letter] = {};
    }
    node = node[letter];
  }
  node.terminal = true;
}

function findLongestMatch(text, start) {
  var node = Global.trie,
      best = start - 1;
  for (var pos = start; pos < text.length; ++pos) {
    var letter = text.charAt(pos);
    if (node[letter] === undefined) {
      break;
    }
    node = node[letter];
    if (node.terminal) {
      best = pos;
    }
  }
  return best - start + 1;
}

function loadTrie() {
  var words = Global.dictionary,
      trie = Global.trie = {};
  words.forEach(function (word) {
    addToTrie(word);
  });
};

function println(label, s, labelStyle) {
  if (s === undefined) {
    s = label || '';
  } else {
    var className = 'label' + (labelStyle ? ' ' + labelStyle : '');
    s = '<div class="' + className + '">' + label + '</div> ' + s;
  }
  document.getElementById('message').innerHTML += (s + '<br />');
}

function process(text) {
  var results = [],
      letters = [],
      pos = 0;
  while (pos < text.length) {
    var length = findLongestMatch(text, pos);
    if (length == 0) {
      letters.push(text.charAt(pos));
      pos += 1;
    } else {
      if (letters.length != 0) {
        results.push({ word: letters.join(''), known: false });
        letters = [];
      }
      results.push({ word: text.substring(pos, pos + length), known: true });
      pos += length;
    }
  }
  if (letters.length != 0) {
    results.push({ word: letters.join(''), known: false });
    letters = [];
  }
  var breakdown = results.map(function (result) {
    return result.word;
  });
  println();
  println('    breakdown:',  '/' + breakdown.join('/') + '/');
  results.forEach(function (result) {
    println((result.known ? 'in dictionary' : '      unknown') + ':',
        '"' + result.word + '"', (result.known ? undefined : 'unknown'));
  });
};

window.onload = function () {
  loadTrie();
  process('WellIamno123prisoner');
  process('TheUSAisveryrichman');
  process('Albertgaveme5rupeesyo');
};
body {
  font-family: monospace;
  color: #444;
  font-size: 14px;
  line-height: 20px;
}
.label {
  display: inline-block;
  width: 200px;
  font-size: 13px;
  color: #aaa;
  text-align: right;
}
.label.unknown {
  color: #c61c39;
}
<div id="message"></div>

答案 1 :(得分:1)

编辑#2

var words = ["apple", "banana", "candy", "cookie", "doughnut"];
var input = "banana123candynotawordcookieblahdoughnut";
var currentWord = "",
    result = "";

while (true) {
    for (var i = 0; i < input.length; i++) {
        currentWord += input[i];
        if (words.indexOf(currentWord) >= 0) {
            result += " " + currentWord + " ";
            currentWord = "";
        }
    }

    if (currentWord.length > 0) {
        result += currentWord[0];
        input = currentWord.substr(1);
        currentWord = "";
    } else {
        break;
    }
}

console.log(result.trim()); // "banana 123 candy notaword cookie blah doughnut"

注意如果有两个连续的字典单词,结果将包含两个空格。您可以使用正则表达式修复此问题。

它不是最漂亮的解决方案(你可以使其递归,可能更具可读性),并且它不提供多种解决方案(请参阅评论中的DP链接)。

编辑这并未考虑非词典单词。

使用简单的贪婪算法:

var words = ["apple", "banana", "candy", "cookie", "doughnut"];
var input = "bananacandycookiedoughnut";
var currentWord = "", result = "";

for (var i = 0; i < input.length; i++) {
    currentWord += input[i];
    if (words.indexOf(currentWord) >= 0) {
        result += currentWord + " ";
        currentWord = "";
    }
}

console.log(result.trim()); // "banana candy cookie donught"

当然你想修改其中的各个部分,例如使用字典集并考虑案例[in]敏感度。