4

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

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

部分条件是文本必须由符号包裹,但如果紧随其后有一个空格,则触发条件无效;所以 * bold* 不会加粗,并且: * notbold but this is bold

innerHTML 将具有已转换为 href 的 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 种模式的 24 种排列中的任何一种一样拥有 4 级深度嵌套样式跨度,例如:

    -!_*SUIB*_!-

谢谢我已经为此奋斗了大约一个星期。

避免 Mozilla 对“标记不应innerHTML动态传递”的不良反馈的奖励积分。(我不明白当一个人改变格式时这怎么可能)。

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

沃尔夫。

更新

使用与上面相同的 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 输出时,我注意到它很高兴没有预先格式化字符串,而是根据需要简单地进行了替换。

因此,在查看了使用 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帖子的条件,我们已经得到了一个完整的工作解决方案。

我还需要添加一个带有结束符号的单字符样式的检查,因为我们要并排替换触发器标记。

正如@acheong87 提醒的那样,小心 \w 因为它包含_, 所以它被添加到除删除线模式之外的所有包装条件中。

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 等)

沃尔夫。

4

3 回答 3

2

试试这些:

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

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

于 2013-03-07T18:27:31.263 回答
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>'
    } );
}

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

应要求提供进一步解释。

于 2013-03-07T20:11:17.020 回答
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)
于 2013-03-08T11:41:00.387 回答