假设我有一个文本字段,用户可以在其中提交代码段。我想检测字符串中何时出现特定单词,然后对 之后的单词/字符执行某些操作。
假设我们有一个字符串,在睡衣之后我想在没有缩进的新行上启动其余代码。 (非常类似于代码美化器的工作方式。)输出将在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,所以如果你愿意,你可以使用它。
这是上面代码的小提琴,所以你可以测试一下。到目前为止,My result并不是很好。 (在textarea中键入内容,输出会发生变化。)由于我目前对正则表达式知之甚少,我需要一些帮助。
到目前为止我所拥有的:
var a = $("textarea").val(),
b = a.split('!').join("!\n "),
c = b.split('pyjamas').join("pyjamas \n");
$("textarea").keyup(function() {
$("#output>pre").html(c);
});
答案 0 :(得分:13)
这是一个简单的方法,不需要递归函数,甚至可以在没有正则表达式的情况下完成(但我觉得这里很方便)。
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
。这很容易处理,但我不知道你的假设或要求是什么。
换行后它也不会处理额外的空格(参见最后的编辑)。
现在是正则表达式:
/
! # 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
modifier,这将使标记化变得更加容易 - 但令人讨厌的是,这个y
修饰符是ECMAScript自己的发明,而提供此功能的所有其他风格都使用\G
锚点模式。
如果你不熟悉正则表达式中的一些更高级的概念,我建议你参考这个很棒的教程:
修改强>
这是一个更新版本,修复了我提到的关于换行后空格的上述警告。在处理结束时,我们只需删除标签后的所有空格:
result = result.replace(/^(\t*)[ ]+/gm, '$1');
正则表达式匹配一行的开头,然后捕获零个或多个标签,然后尽可能多的空格。空间周围的方括号不是必需的,但提高了可读性。修饰符g
再次找到所有此类匹配,m
使^
匹配行的开头(而不仅仅是字符串的开头)。在替换字符串$1
中指的是我们在括号中捕获的内容 - 即所有这些标签。所以回写标签,但吞下空格。
答案 1 :(得分:2)
与m.buettner解决方案没有什么不同,你可以使用replace方法:
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"); });
});
});
注意:定义一个稍后可以重用的函数可能会更加干净。