正则表达式 - 格式化块中的文本 - IM

时间:2013-03-07 18:16:48

标签: javascript regex algorithm instant-messaging

您好我正在尝试找出一个正则表达式来替换innerHTML块中的文本,以便为与Google IM操作类似的文本提供本地格式。

Where: 
_Italics_
!Inderline!
*Bold*
-Strike-

部分条件是文本必须用符号包裹,但如果之后紧跟空格,则触发条件无效;所以* bold *不会加粗和:* notbold 但是这是粗体

innerHTML将具有已经转换为hrefs的URL,所以为了不弄乱它们,我在我的正则表达式的前面添加了以下内容。

    (?!(?!.*?<a)[^<]*<\/a>)

以下javascript无法捕获所有结果,并且根据我进行替换的顺序会有不同的结果。

var boldPattern          = /(?!(?!.*?<a)[^<]*<\/a>)\*([^\s]+[\s\S]?[^\s]+)\*([\s_!-]?)/gi;
var italicsPattern       = /(?!(?!.*?<a)[^<]*<\/a>)_([^\s]+[\s\S]?[^\s]+)_([\s-!\*]?)/gi;
var strikethroughPattern = /(?!(?!.*?<a)[^<]*<\/a>)-([^\s]+[\s\S]?[^\s]+)-([\s_!\*]?)/gi;
var underlinePattern     = /(?!(?!.*?<a)[^<]*<\/a>)!([^\s]+[\s\S]?[^\s]+)!([\s-_\*]?)/gi;
str = str.replace(strikethroughPattern, '<span style="text-decoration:line-through;">$1</span>$2');
str = str.replace(boldPattern, '<span style="font-weight:bold;">$1</span>$2');
str = str.replace(underlinePattern, '<span style="text-decoration:underline;">$1</span>$2');
str = str.replace(italicsPattern, '<span style="font-style:italic;">$1</span>$2');

3选择4的测试数据如下:

1 _-*ISB*-_ 2 _-!ISU!-_ 3 _*-IBS-*_ 4 _*!IBU!*_
5 _!-IUS-!_ 6 _!*IUB*!_ 7 -_*SIB*_- 8 -_!SIU!_-
9 -*_SBI_*- 10 -*!SBU!*- 11 -!_SUI_!- 12 -!*SIB*!-
13 *_-BIS-_* 14 *_!BIU!_* 15 *-_BSI_-* 16 *-!BSU!-*
17 *!_BUI_!* 18 *!-BUS-!* 19 !_-UIS-_! 20 !_*UIB*_!
21 !-_USI_-! 22 !-*USB*-! 23 !*_UBI_*! 24 !*-UBS-*!

你是否可以拥有4级深嵌套样式范围,就像选择所有4种模式的24种排列中的任何一种一样:

    -!_*SUIB*_!-

谢谢,我已经打了一个星期了。

用于避免Mozilla的错误反馈的加分点“不应该动态地将标记传递给innerHTML”。 (当我们改变格式时,我不明白这是怎么可能的。)

感谢一百万个正则表达式向导!我欠你的债。

mwolfe。

更新

使用与上述相同的href检测和@talemyn帮助我们现在位于:

var boldPattern          = /(?!(?!.*?<a)[^<]*<\/a>)\*([^\s][^\*]*)\*/gi;
var italicsPattern       = /(?!(?!.*?<a)[^<]*<\/a>)_([^\s][^_]*)_/gi;
var strikethroughPattern = /(?!(?!.*?<a)[^<]*<\/a>)-([^\s][^-]*)-/gi;
var underlinePattern     = /(?!(?!.*?<a)[^<]*<\/a>)!([^\s][^!]*)!/gi;
str = str.replace(strikethroughPattern, '<s>$1</s>');
str = str.replace(italicsPattern, '<span style="font-style:italic;">$1</span>');
str = str.replace(boldPattern, '<strong>$1</strong>');
str = str.replace(underlinePattern, '<u>$1</u>');

这似乎涵盖了一个极端的例子:

    _wow *a real* !nice *person! on -stackoverflow* figured- it out_ cool beans.

我认为可以使用样式跨度并执行正则表达式回顾以确定先前未闭合的跨度,关闭它,使用旧格式加上新属性打开新跨度,在假设时关闭并打开新跨度以完成格式化。但正如@NovaDenizen指出的那样,正则表达式可能会变得混乱或不可能。

感谢您的帮助。如果有任何改进,请告诉我。注意:我无法使用,因为网站上的CSS无法呈现它。可以超负荷吗? [这是针对firefox / greasemonkey / chrome插件]

更新(差不多)最终

使用我的'破损'测试短语,正如@MikeM正确指出的那样,作为一个例子,无论是否正确嵌套,它都会在Google IM中正确呈现(减去下划线)。因此,从Google IM中的文本中查看HTML输出,我注意到它很高兴没有预先格式化sting,但是简单地根据需要替换了。

因此,在查看使用resetcss删除的站点代码后,我需要通过javascript插入CSS格式。 Stackoverflow救援。 https://stackoverflow.com/questions/707565/how-do-you-add-css-with-javascripthttps://stackoverflow.com/questions/20107/yui-reset-css-makes-strongemthis-not-work-em-strong

所以我的解决方案现在看起来像:

....
var css = document.createElement("style");
css.type = "text/css";
css.innerHTML = "strong, b, strong *, b * { font-weight: bold !important; } \
            em, i, em *, i * { font-style: italic !important; }";
document.body.appendChild(css);
 ....
var boldPattern          = /(?!(?!.*?<a)[^<]*<\/a>)\*([^\s][^\*]*)\*/gi;
var italicsPattern       = /(?!(?!.*?<a)[^<]*<\/a>)_([^\s][^_]*)_/gi;
var strikethroughPattern = /(?!(?!.*?<a)[^<]*<\/a>)-([^\s][^-]*)-/gi;
var underlinePattern     = /(?!(?!.*?<a)[^<]*<\/a>)!([^\s][^!]*)!/gi;
str = str.replace(strikethroughPattern, '<s>$1</s>');
str = str.replace(italicsPattern, '<i>$1</i>');
str = str.replace(boldPattern, '<b>$1</b>');
str = str.replace(underlinePattern, '<u>$1</u>');
.....

tada它主要起作用!

更新最终解决方案 在对@MikeM的锚元素检查进行最后一分钟简化并结合另一个stackoverflow帖子的条件后,我们得出了一个完整的工作解决方案。

我还需要添加一个带有结束符号的char样式的检查,因为我们并排替换触发令牌。

由于@ acheong87提醒要注意\ w,因为它包含_,因此除了strikethroughPattern之外,它被添加到包装条件中。

var boldPattern          = /(?![^<]*<\/a>)(^|<.>|[\s\W_])\*(\S.*?\S)\*($|<\/.>|[\s\W_])/g;
var italicsPattern       = /(?![^<]*<\/a>)(^|<.>|[\s\W])_(\S.*?\S)_($|<\/.>|[\s\W])/g;
var strikethroughPattern = /(?![^<]*<\/a>)(^|<.>|[\s\W_])-(\S.*?\S)-($|<\/.>|[\s\W_])/gi;
var underlinePattern     = /(?![^<]*<\/a>)(^|<.>|[\s\W_])!(\S.*?\S)!($|<\/.>|[\s\W_])/gi;
str = str.replace(strikethroughPattern, '$1<s>$2</s>$3');
str = str.replace(italicsPattern, '$1<i>$2</i>$3');
str = str.replace(boldPattern, '$1<b>$2</b>$3');
str = str.replace(underlinePattern, '$1<u>$2</u>$3');

非常感谢大家(@MikeM,@ talemyn,@ acheong87,等)

mwolfe。

3 个答案:

答案 0 :(得分:1)

试试这些:

var boldPattern          = /\*([^\s][^\*]*)\*/gi;
var italicsPattern       = /_([^\s][^_]*)_/gi;
var strikethroughPattern = /-([^\s][^-]*)-/gi;
var underlinePattern     = /!([^\s][^!]*)!/gi;

尽管在replace中,请不要使用$2,因为这些正则表达式模式中没有第二个匹配。

答案 1 :(得分:1)

以下内容不应创建错误的嵌套跨度

var old;
var rx = /(?![^<]*(?:>|<\/a>))([!*_-])((?!\1)[^<>\s][^<>]*?)\1/g;

while ( old != str ) {
    old = str;
    str = str.replace( rx, function ( $0, $1, $2 ) {
        var style = $1 == '!' ? "text-decoration:underline"
                  : $1 == '*' ? "font-weight:bold"
                  : $1 == '_' ? "font-style:italic"
                              : "text-decoration:line-through";

        return  '<span style="' + style + ';">' + $2 + '</span>'
    } );
}

因为它首先替换外部分隔符,所以不应该在分隔符内插入任何跨度。

请求进一步说明。

答案 2 :(得分:1)

我建议您从负面预测中移除内部负面预测:

/(?!(?!.*?<a)[^<]*<\/a>)_it_/.test( ' _it_ <a></a>' );         // true  (correct)
/(?!(?!.*?<a)[^<]*<\/a>)_it_/.test( '<a> _it_ </a>' );         // false (correct)
/(?!(?!.*?<a)[^<]*<\/a>)_it_/.test( '<a> _it_ </a> <a></a>' ); // true  (wrong)

/(?![^<]*<\/a>)_it_/.test( ' _it_ <a></a>' );                  // true  (correct)
/(?![^<]*<\/a>)_it_/.test( '<a> _it_ </a>' );                  // false (correct)
/(?![^<]*<\/a>)_it_/.test( '<a> _it_ </a> <a></a>' );          // false (correct)