首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在特定单词之后中断字符串,并将其放在新行上(Regex)

在特定单词之后中断字符串,并将其放在新行上(Regex)
EN

Stack Overflow用户
提问于 2014-03-07 19:43:59
回答 2查看 3.1K关注 0票数 8

假设我有一个文本字段,用户可以在其中提交代码片段。我希望检测字符串中某个特定的单词何时出现,然后对该单词后面的单词/字符做一些操作。

比方说,我们有一个字符串,在“睡衣”这个词之后,我想在一个新的行上启动剩下的代码,没有缩进。(非常类似于代码美化器的工作方式。)输出将在pre中呈现,因此我不需要任何<br>标记或其他HTML标记。

不过还是有一些收获的。

  1. 单词后面的所有内容(睡衣)都必须在与前面的行相同的“级别”(相同数量的制表符缩进)上开始。
  2. 逗号应该总是从新行开始,然后用制表符反向缩进。
  3. 当有另一个字符时,假设是感叹号!,下面的代码必须以新行开始,并以制表符作为缩进。

示例:

输入

代码语言:javascript
复制
Bananas! Apples and pears walk down pyjamas the street! and they say pyjamas hi to eachother, pyjamas But then! some one else comes pyjamas along pyjamas Who is he?, pyjamas I don't know who! he is pyjamas whatever,,

输出

代码语言:javascript
复制
Bananas!
    Apples and pears walk down pyjamas
    the street!
        and they say pyjamas
        hi to eachother
    , pyjamas
    But then!
        some one else comes pyjamas
        along pyjamas
        Who is he?
    , pyjamas
    I don't know who!
        he is pyjamas
        whatever
    ,
,

我正在使用jQuery,所以如果您愿意,可以使用它。

下面是对上面的代码的修改,这样您就可以测试它了。到目前为止,我的结果一点也不太好。(在textarea中键入某些内容,输出将发生变化。)由于我目前对regex几乎不了解,所以我需要一些帮助。

到目前为止我所拥有的是:

代码语言:javascript
复制
var a = $("textarea").val(),
    b = a.split('!').join("!\n  "),
    c = b.split('pyjamas').join("pyjamas \n");

$("textarea").keyup(function() {
    $("#output>pre").html(c);
});
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-03-09 23:21:18

这里有一种简单的方法,它不需要递归函数,甚至可以不使用正则表达式(但我在这里发现它们很方便)。

代码语言:javascript
复制
function indent(str)
{
    var tabs = function(n) { return new Array(n+1).join('\t'); }

    var tokens = str.match(/!|,|pyjamas|(?:(?!pyjamas)[^!,])+/g);
    var depth = 0;
    var result = '';
    for (var i = 0; i < tokens.length; ++i)
    {
        var token = tokens[i];
        switch(token)
        {
        case '!':
            ++depth;
            result += token + '\n' + tabs(depth);
            break;
        case ',':
            --depth;
            result += '\n' + tabs(depth) + token;
            break;
        case 'pyjamas':
            result += token + '\n' + tabs(depth);
            break;
        default:
            result += token;
            break;
        }
    }
    return result;
}

首先,我们定义了一个返回n选项卡字符串的函数(为了方便起见)。

然后我们将这个过程分成两个步骤。首先,我们把字符串分解成!,pyjamas和其他任何东西。(最终对正则表达式有一个解释,但你也可以用其他方式进行标记化。)然后,我们简单地一个一个地遍历令牌,保持depth中当前的缩进水平。

  • 如果是!,我们会增加深度,打印!、换行和制表符。
  • 如果它是一个,,我们减少深度,打印一个断线,制表符,然后,
  • 如果是pyjamas,我们只需打印它和一个换行符和制表符。
  • 如果是其他的话,我们只需打印那个记号。

就这样。您可能需要添加一些正确的检查,确保深度不会变为负值(也就是说,您的,!更多)--目前,它只是在没有任何选项卡的情况下呈现,但是您需要在此之后编写额外的!,以便将深度恢复到1。这很容易处理,但我不知道你对此的假设或要求是什么。

它还没有处理行中断后的额外空格(请参阅末尾的编辑)。

工作演示。

现在是regex:

代码语言:javascript
复制
/
  !               # Match a literal !
|                 # OR
  ,               # Match a literal ,
|                 # OR
  pyjamas         # Match pyjamas
|                 # OR
  (?:             # open a non-capturing group
    (?!pyjamas)   # make sure that the next character is not the 'p' of 'pyjamas'
    [^!,]         # match a non-!, non-, character
  )+              # end of group, repeat once or more (as often as possible)
/g

查找所有匹配项的g (而不是第一个匹配项)。ECMAScript 6将附带一个修饰符,这将使令牌化更加容易--但令人恼怒的是,这个y修饰符是ECMAScript自己发明的,而提供此功能的其他所有特性都在模式中使用\G锚点。

如果regex中的一些更高级的概念不为您所熟悉,我将向您介绍这个伟大的教程:

  • 否定字符类
  • 非捕获群
  • 看头

编辑:

这里是一个更新的版本,修复了我提到的关于换行后空格的上述警告。在处理结束时,我们只需删除制表符后的所有空格:

代码语言:javascript
复制
result = result.replace(/^(\t*)[ ]+/gm, '$1');

正则表达式匹配一行的开头,然后捕获零或多个制表符,然后尽可能多地捕获空格。空格周围的方括号是不必要的,但可以提高可读性。修饰符g再次查找所有这样的匹配,m使^在行的开头(而不是字符串的开头)匹配。在替换字符串中,$1指的是我们在括号中捕获的内容,即所有这些选项卡。所以,把制表符写回去,然后吞下空格。

工作演示。

票数 13
EN

Stack Overflow用户

发布于 2014-03-12 15:14:18

与m.buettner解决方案没有太大区别,您可以使用替换方法来完成:

代码语言:javascript
复制
var lvl = 1;
var res = str.replace(/(!)\s*|\s*(,)|(\bpyjamas)\s+/g, function (m, g1, g2, g3) {
    if (g1) return g1 + "\n" + Array(++lvl).join("\t");
    if (g2) return "\n" + Array((lvl>1)?--lvl:lvl).join("\t") + g2;
    return g3 + "\n" + Array(lvl).join("\t"); });

console.log(res);

其思想是使用三个不同的捕获组,并在回调函数中测试它们。根据捕获组的不同,级别是递增或递减的(地面为1级)。当级别为1并且找到逗号时,级别停留设置为1。我添加了\s*\s+,以在逗号之前和!pyjamas之后修剪空格。如果你不想要这个,你可以把它移除。

使用您的代码:

代码语言:javascript
复制
$("#output>pre").html($("textarea").val());

$("textarea").keyup(function() {
    $("#output>pre").html(function() {
        var lvl = 1;
        return $("textarea").val().replace(/(!)\s*|\s*(,)|(\bpyjamas)\s+/g,
            function (m, g1, g2, g3) {
                if (g1) return g1 + "\n" + Array(++lvl).join("\t");
                if (g2) return "\n" + Array((lvl>1)?--lvl:lvl).join("\t") + g2;
                return g3 + "\n" + Array(lvl).join("\t"); });
    });
});

注意:定义一个以后可以重用的函数可能更清晰。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22259272

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档