假设我有一个文本字段,用户可以在其中提交代码片段。我希望检测字符串中某个特定的单词何时出现,然后对该单词后面的单词/字符做一些操作。
比方说,我们有一个字符串,在“睡衣”这个词之后,我想在一个新的行上启动剩下的代码,没有缩进。(非常类似于代码美化器的工作方式。)输出将在pre中呈现,因此我不需要任何<br>标记或其他HTML标记。
不过还是有一些收获的。
!,下面的代码必须以新行开始,并以制表符作为缩进。示例:
输入
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,,输出
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几乎不了解,所以我需要一些帮助。
到目前为止我所拥有的是:
var a = $("textarea").val(),
b = a.split('!').join("!\n "),
c = b.split('pyjamas').join("pyjamas \n");
$("textarea").keyup(function() {
$("#output>pre").html(c);
});发布于 2014-03-09 23:21:18
这里有一种简单的方法,它不需要递归函数,甚至可以不使用正则表达式(但我在这里发现它们很方便)。
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:
/
! # 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中的一些更高级的概念不为您所熟悉,我将向您介绍这个伟大的教程:
编辑:
这里是一个更新的版本,修复了我提到的关于换行后空格的上述警告。在处理结束时,我们只需删除制表符后的所有空格:
result = result.replace(/^(\t*)[ ]+/gm, '$1');正则表达式匹配一行的开头,然后捕获零或多个制表符,然后尽可能多地捕获空格。空格周围的方括号是不必要的,但可以提高可读性。修饰符g再次查找所有这样的匹配,m使^在行的开头(而不是字符串的开头)匹配。在替换字符串中,$1指的是我们在括号中捕获的内容,即所有这些选项卡。所以,把制表符写回去,然后吞下空格。
工作演示。
发布于 2014-03-12 15:14:18
与m.buettner解决方案没有太大区别,您可以使用替换方法来完成:
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之后修剪空格。如果你不想要这个,你可以把它移除。
使用您的代码:
$("#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"); });
});
});注意:定义一个以后可以重用的函数可能更清晰。
https://stackoverflow.com/questions/22259272
复制相似问题