如何通过空格和标点符号拆分JavaScript字符串?

14

我有一些随机字符串,例如:Hello, my name is john.。我希望将这个字符串分割成一个数组,就像这样:Hello, ,, , my, name, is, john, .,。我尝试使用str.split(/[^\w\s]|_/g),但它似乎无效。有什么想法吗?


@davin:在正则表达式中使用捕获括号将把捕获的结果插入到生成的数组中,但它也包括空格。我无法仅使用“split”和正则表达式获得完全匹配的结果。 - Reid
4个回答

26

将字符串按任何非单词字符的连续出现进行拆分。即不是 A-Z、0-9 和下划线。

var words=str.split(/\W+/);  // assumes str does not begin nor end with whitespace

假设你的目标语言是英语,你可以使用以下方法从字符串中提取所有语义上有用的值(即将字符串“标记化”):

var str='Here\'s a (good, bad, indifferent, ...) '+
        'example sentence to be used in this test '+
        'of English language "token-extraction".',

    punct='\\['+ '\\!'+ '\\"'+ '\\#'+ '\\$'+   // since javascript does not
          '\\%'+ '\\&'+ '\\\''+ '\\('+ '\\)'+  // support POSIX character
          '\\*'+ '\\+'+ '\\,'+ '\\\\'+ '\\-'+  // classes, we'll need our
          '\\.'+ '\\/'+ '\\:'+ '\\;'+ '\\<'+   // own version of [:punct:]
          '\\='+ '\\>'+ '\\?'+ '\\@'+ '\\['+
          '\\]'+ '\\^'+ '\\_'+ '\\`'+ '\\{'+
          '\\|'+ '\\}'+ '\\~'+ '\\]',

    re=new RegExp(     // tokenizer
       '\\s*'+            // discard possible leading whitespace
       '('+               // start capture group
         '\\.{3}'+            // ellipsis (must appear before punct)
       '|'+               // alternator
         '\\w+\\-\\w+'+       // hyphenated words (must appear before punct)
       '|'+               // alternator
         '\\w+\'(?:\\w+)?'+   // compound words (must appear before punct)
       '|'+               // alternator
         '\\w+'+              // other words
       '|'+               // alternator
         '['+punct+']'+        // punct
       ')'                // end capture group
     );

// grep(ary[,filt]) - filters an array
//   note: could use jQuery.grep() instead
// @param {Array}    ary    array of members to filter
// @param {Function} filt   function to test truthiness of member,
//   if omitted, "function(member){ if(member) return member; }" is assumed
// @returns {Array}  all members of ary where result of filter is truthy
function grep(ary,filt) {
  var result=[];
  for(var i=0,len=ary.length;i++<len;) {
    var member=ary[i]||'';
    if(filt && (typeof filt === 'Function') ? filt(member) : member) {
      result.push(member);
    }
  }
  return result;
}

var tokens=grep( str.split(re) );   // note: filter function omitted 
                                     //       since all we need to test 
                                     //       for is truthiness

这将产生:


tokens=[ 
  'Here\'s',
  'a',
  '(',
  'good',
  ',',
  'bad',
  ',',
  'indifferent',
  ',',
  '...',
  ')',
  'example',
  'sentence',
  'to',
  'be',
  'used',
  'in',
  'this',
  'test',
  'of',
  'English',
  'language',
  '"',
  'token-extraction',
  '"',
  '.'
]

编辑

还可以作为Github Gist获取。


4
split(/\W+/) 可以去除所有非英文字符。但切勿用于姓名的分割。 - Dan Abramov

11

试试这个(我不确定这是否是你想要的):

str.replace(/[^\w\s]|_/g, function ($1) { return ' ' + $1 + ' ';}).replace(/[ ]+/g, ' ').split(' ');

http://jsfiddle.net/zNHJW/3/


@chromedude 最后一部分可以缩短为这种形式:str.replace(/[^\w\s]|_/g, function ($1) { return ' ' + $1 + ' ';}).split(/[ ]+/g);。我只是不习惯使用正则表达式的split方法。 - pepkin88

6

尝试:

str.split(/([_\W])/)

这将按照任何非字母数字字符(\W)和任何下划线进行拆分。它使用捕获括号来在最终结果中包含被拆分的项。


由于\W表示任何不是A-Z、0-9或下划线的字符,因此您可以将/[\W\s_]/简化为/\W/以达到相同的效果。要将下划线添加到您的不可接受字符列表中,请将其添加到字符类的开头以提高效率。 - Rob Raisch
@Rob:在\s方面我比你快。不过我会把下划线放在前面,谢谢。 - Reid
括号是多余的,因为没有必要捕获任何内容,应该删除它们,因为它们的添加会增加执行时间。此外,字符类需要附加一个加号(以匹配一个或多个),除非您想要空结果。因此,完整的表达式应为“str.split(/[_\W]+/)”(我添加了反斜杠转义到下划线,即使不需要,也是为了可读性)。 - Rob Raisch
@Rob:括号不是多余的。它们会改变结果。我也没有在你的完整表达式中看到反斜杠。 - Reid
当然,你是正确的。我错过了那个。一个考虑因素是,在正则表达式中使用捕获确实会增加其执行时间,因此,如果速度是一个问题,也许在所有非目标值上进行拆分可能是更好的方法。 - Rob Raisch

1
这个解决方案对我来说存在空格的挑战(仍然需要它们),然后我尝试了str.split(/\b/),一切都很好。空格会在数组中输出,不难忽略,在标点符号后剩下的可以被修剪掉。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接