Javascript 和正则表达式:拆分字符串并保留分隔符

Posted

技术标签:

【中文标题】Javascript 和正则表达式:拆分字符串并保留分隔符【英文标题】:Javascript and regex: split string and keep the separator 【发布时间】:2012-08-13 16:12:48 【问题描述】:

我有一个字符串:

var string = "aaaaaa<br />&dagger; bbbb<br />&Dagger; cccc"

我想用分隔符&lt;br /&gt; 后跟一个特殊字符来分割这个字符串。

为此,我正在使用这个:

string.split(/<br \/>&#?[a-zA-Z0-9]+;/g);

我得到了我需要的东西,除了我丢失了分隔符。 示例如下:http://jsfiddle.net/JwrZ6/1/

如何保留分隔符?

【问题讨论】:

如果你事先知道分隔符,为什么不干... var delim = "&lt;br/&gt;"; ? 谢谢@SiGanteng,我知道预先的分隔符,但我无法让它适用于我的示例。我需要将分隔符保持为 后跟特殊字符,因为有时我可以有一个 后面没有特殊字符,而这个不必拆分。 好问题,我有一个类似的情况,知道分隔符没有帮助。我正在拆分“]&[”。所以真的我的分隔符是“&”,但分割不够精确,我需要两边的括号来确定正确的分割。但是,我需要将这些括号放回我的拆分字符串中。每边各 1 个。 @PandaWood 所以,这些天你会使用.split(/(?&lt;=\[)&amp;(?=[)/) 【参考方案1】:

我遇到了类似但略有不同的问题。无论如何,这里是三个不同场景的示例,用于在何处保留分隔符。

"1、2、3".split("、") == ["1", "2", "3"]
"1、2、3".split(/(、)/g) == ["1", "、", "2", "、", "3"]
"1、2、3".split(/(?=、)/g) == ["1", "、2", "、3"]
"1、2、3".split(/(?!、)/g) == ["1、", "2、", "3"]
"1、2、3".split(/(.*?、)/g) == ["", "1、", "", "2、", "3"]

警告:第四个只能拆分单个字符。 ConnorsFan 呈现an alternative:

// Split a path, but keep the slashes that follow directories
var str = 'Animation/rawr/javascript.js';
var tokens = str.match(/[^\/]+\/?|\//g);

【讨论】:

我正在寻找类似第三个示例的内容,但这仅适用于元素只有一个字符的情况 - 否则它将拆分为单个字符。最后我不得不走乏味的RegExp.exec路线。 我不明白为什么每个人都在使用 /g 如何使用这个正则表达式 "1、2、3".split(/(?!、)/g) == ["1、", "2、", "3"]完整的话?例如 "foo1, foo2, foo3," 你是个天才!在哪里可以找到解释其工作方式的文档?你不需要g 结束 .match 这些示例的非贪婪解决方案的翻译:"11、22、33".match(/.*?、|.+$/g) -> ["11、", "22、", "33"]。注意/g 修饰符对于匹配至关重要。【参考方案2】:

使用(positive) lookahead,以便正则表达式断言特殊字符存在,但实际上并不匹配:

string.split(/<br \/>(?=&#?[a-zA-Z0-9]+;)/g);

查看实际操作:

var string = "aaaaaa<br />&dagger; bbbb<br />&Dagger; cccc";
console.log(string.split(/<br \/>(?=&#?[a-zA-Z0-9]+;)/g));

【讨论】:

当我使用这段代码时,它会在每个字符串的末尾添加一个0 我在您提供的链接中找不到任何关于积极前瞻的信息。 @PaulJones 内容在中间时间被移动。感谢您告诉我,我已修复链接。 当我回到这个问题时为自己评论:'positive' lookahead is (?=) Torsten Walter 的回答要好一些,因为分隔符被放入了它们自己的数组项中。更容易操作。【参考方案3】:

如果将分隔符用括号括起来,它将成为返回数组的一部分。

string.split(/(<br \/>&#?[a-zA-Z0-9]+);/g);
// returns ["aaaaaa", "<br />&dagger;", "bbbb", "<br />&Dagger;", "cccc"]

根据您要保留的部分更改匹配的子组

string.split(/(<br \/>)&#?[a-zA-Z0-9]+;/g);
// returns ["aaaaaa", "<br />", "bbbb", "<br />", "cccc"]

您可以通过忽略字母的大小写来改进表达 string.split(/()?[a-z0-9]+;/gi);

您可以像这样匹配预定义组:\d 等于 [0-9]\w 等于 [a-zA-Z0-9_]。这意味着您的表达式可能看起来像这样。

string.split(/<br \/>(&#?[a-z\d]+;)/gi);

有一个很好的Regular Expression Reference on JavaScriptKit。

【讨论】:

更好的是,我不知道我们只能保留分隔符的一部分。事实上我只需要保留特殊字符,我可以这样做:string.split(/(?[a-zA-Z0-9]+;)/g);跨度> 您可以通过忽略单词的大小写来优化您的表达。或匹配预定义的字符类。我会更新我的答案。 为什么这么低..它完美又灵活 这当然是最简单的方法,也是最易读的语法。【参考方案4】:

这里也回答了JavaScript Split Regular Expression keep the delimiter

在正则表达式中使用 (?=pattern) 前瞻模式 例子

var string = '500x500-11*90~1+1';
string = string.replace(/(?=[$-/:-?-~!"^_`\[\]])/gi, ",");
string = string.split(",");

这将为您提供以下结果。

[ '500x500', '-11', '*90', '~1', '+1' ]

也可以直接拆分

string = string.split(/(?=[$-/:-?-~!"^_`\[\]])/gi);

给出相同的结果

[ '500x500', '-11', '*90', '~1', '+1' ]

【讨论】:

为什么不像 Jon 接受的答案那样立即拆分? @Gordon... :) 我可以这样做...更新了代码...干杯【参考方案5】:

我对jichi的回答做了修改,放到一个也支持多字母的函数中。

String.prototype.splitAndKeep = function(separator, method='seperate')
    var str = this;
    if(method == 'seperate')
        str = str.split(new RegExp(`($separator)`, 'g'));
    else if(method == 'infront')
        str = str.split(new RegExp(`(?=$separator)`, 'g'));
    else if(method == 'behind')
        str = str.split(new RegExp(`(.*?$separator)`, 'g'));
        str = str.filter(function(el)return el !== "";);
    
    return str;
;

jichi's answers 第三种方法在这个函数中不起作用,所以我采取了第四种方法,并删除了空格以获得相同的结果。

编辑: 第二种方法,除了数组来拆分 char1 或 char2

String.prototype.splitAndKeep = function(separator, method='seperate')
    var str = this;
    function splitAndKeep(str, separator, method='seperate')
        if(method == 'seperate')
            str = str.split(new RegExp(`($separator)`, 'g'));
        else if(method == 'infront')
            str = str.split(new RegExp(`(?=$separator)`, 'g'));
        else if(method == 'behind')
            str = str.split(new RegExp(`(.*?$separator)`, 'g'));
            str = str.filter(function(el)return el !== "";);
        
        return str;
    
    if(Array.isArray(separator))
        var parts = splitAndKeep(str, separator[0], method);
        for(var i = 1; i < separator.length; i++)
            var partsTemp = parts;
            parts = [];
            for(var p = 0; p < partsTemp.length; p++)
                parts = parts.concat(splitAndKeep(partsTemp[p], separator[i], method));
            
        
        return parts;
    else
        return splitAndKeep(str, separator, method);
    
;

用法:

str = "first1-second2-third3-last";

str.splitAndKeep(["1", "2", "3"]) == ["first", "1", "-second", "2", "-third", "3", "-last"];

str.splitAndKeep("-") == ["first1", "-", "second2", "-", "third3", "-", "last"];

【讨论】:

非常有用!谢谢!仅供路过的人使用...这将拆分为单独的元素换行符。如果您不想要这种行为,请使用“gs”而不是“g”【参考方案6】:

扩展函数用子字符串或正则表达式分割字符串,分隔符根据第二个参数放在前面或后面。

    String.prototype.splitKeep = function (splitter, ahead) 
        var self = this;
        var result = [];
        if (splitter != '') 
            var matches = [];
            // Getting mached value and its index
            var replaceName = splitter instanceof RegExp ? "replace" : "replaceAll";
            var r = self[replaceName](splitter, function (m, i, e) 
                matches.push( value: m, index: i );
                return getSubst(m);
            );
            // Finds split substrings
            var lastIndex = 0;
            for (var i = 0; i < matches.length; i++) 
                var m = matches[i];
                var nextIndex = ahead == true ? m.index : m.index + m.value.length;
                if (nextIndex != lastIndex) 
                    var part = self.substring(lastIndex, nextIndex);
                    result.push(part);
                    lastIndex = nextIndex;
                
            ;
            if (lastIndex < self.length) 
                var part = self.substring(lastIndex, self.length);
                result.push(part);
            ;
            // Substitution of matched string
            function getSubst(value) 
                var substChar = value[0] == '0' ? '1' : '0';
                var subst = '';
                for (var i = 0; i < value.length; i++) 
                    subst += substChar;
                
                return subst;
            ;
        
        else 
            result.add(self);
        ;
        return result;
    ;

测试:

    test('splitKeep', function () 
        // String
        deepEqual("1231451".splitKeep('1'), ["1", "231", "451"]);
        deepEqual("123145".splitKeep('1', true), ["123", "145"]);
        deepEqual("1231451".splitKeep('1', true), ["123", "145", "1"]);
        deepEqual("hello man how are you!".splitKeep(' '), ["hello ", "man ", "how ", "are ", "you!"]);
        deepEqual("hello man how are you!".splitKeep(' ', true), ["hello", " man", " how", " are", " you!"]);
        // Regex
        deepEqual("mhellommhellommmhello".splitKeep(/m+/g), ["m", "hellomm", "hellommm", "hello"]);
        deepEqual("mhellommhellommmhello".splitKeep(/m+/g, true), ["mhello", "mmhello", "mmmhello"]);
    );

【讨论】:

【参考方案7】:

我一直在用这个:

String.prototype.splitBy = function (delimiter) 
  var 
    delimiterPATTERN = '(' + delimiter + ')', 
    delimiterRE = new RegExp(delimiterPATTERN, 'g');

  return this.split(delimiterRE).reduce((chunks, item) => 
    if (item.match(delimiterRE))
      chunks.push(item)
     else 
      chunks[chunks.length - 1] += item
    ;
    return chunks
  , [])

除了你不应该乱用String.prototype,所以这里是一个函数版本:

var splitBy = function (text, delimiter) 
  var 
    delimiterPATTERN = '(' + delimiter + ')', 
    delimiterRE = new RegExp(delimiterPATTERN, 'g');

  return text.split(delimiterRE).reduce(function(chunks, item)
    if (item.match(delimiterRE))
      chunks.push(item)
     else 
      chunks[chunks.length - 1] += item
    ;
    return chunks
  , [])

所以你可以这样做:

var haystack = "aaaaaa<br />&dagger; bbbb<br />&Dagger; cccc"
var needle =  '<br \/>&#?[a-zA-Z0-9]+;';
var result = splitBy(haystack , needle)
console.log( JSON.stringify( result, null, 2) )

你最终会得到:

[
  "<br />&dagger; bbbb",
  "<br />&Dagger; cccc"
]

【讨论】:

【参考方案8】:

如果您对拆分模式进行分组,则其匹配项将保留在输出中,这是设计使然:

如果separator是一个带括号的正则表达式,那么 每次分隔符匹配时,结果(包括任何未定义的 捕获括号的结果)被拼接到输出中 数组。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split#description

您不需要前瞻或全局标志,除非您的搜索模式使用一个。

const str = `How much wood would a woodchuck chuck, if a woodchuck could chuck wood?`

const result = str.split(/(\s+)/);
console.log(result);

// We can verify the result
const isSame = result.join('') === str;
console.log( isSame );

您可以使用多个组。您可以随心所欲地发挥创意,组外的内容将被删除:

const str = `How much wood would a woodchuck chuck, if a woodchuck could chuck wood?`

const result = str.split(/(\s+)(\w1,2)\w+/);
console.log(result, result.join(''));

【讨论】:

【参考方案9】:

大多数现有答案早于 2018 年在 JavaScript 中引入 lookbehind assertions。您没有指定如何将分隔符包含在结果中。一个典型的用例是用标点符号 ([.?!]) 分隔的句子,人们希望在结果字符串的末尾包含分隔符。这对应于接受的答案中的第四种情况,但正如那里指出的那样,该解决方案仅适用于单个字符。末尾附加分隔符的任意字符串可以通过后向断言形成:

'It is. Is it? It is!'.split(/(?<=[.?!])/)
/* [ 'It is.', ' Is it?', ' It is!' ] */

【讨论】:

【参考方案10】:

我也想出了这个解决方案。不需要正则表达式,非常易读。

const str = "hello world what a great day today balbla"
const separatorIndex = str.indexOf("great")
const parsedString = str.slice(separatorIndex)

console.log(parsedString)

或一行:

const str = "hello what a great day today balbla"
const parsedString = str.indexOf(str.indexOf("great"))
console.log(parsedString)

【讨论】:

以上是关于Javascript 和正则表达式:拆分字符串并保留分隔符的主要内容,如果未能解决你的问题,请参考以下文章

如何在 JavaScript 中将长正则表达式拆分为多行?

如何使用 JavaScript 正则表达式拆分此文本?

在javascript中将字符串拆分为匹配和不匹配的组

JavaScript正则表达式

Java如何拆分正则表达式和字符串?

javascript正则