Javascript 正则表达式不匹配部分序列,但匹配完整序列
我有一些转义HTML,如下所示:Javascript 正则表达式不匹配部分序列,但匹配完整序列,javascript,regex,Javascript,Regex,我有一些转义HTML,如下所示: <img border='0' /> 我试图匹配并替换完整的转义序列,如'但不是部分的,如39,因为39实际上不在未转换字符串中。本质上,每个转义序列都应该被视为一个标记 这是一个JS正则表达式。是否有方法排除&和之间的匹配同时仍接受包含这两个字符的序列 预期结果: 搜索img边框=';0' /对于lt:不匹配 搜索img边框=';0' /对于39:不
<img border='0' />
我试图匹配并替换完整的转义序列,如'代码>但不是部分的,如39
,因为39
实际上不在未转换字符串中。本质上,每个转义序列都应该被视为一个标记
这是一个JS正则表达式。是否有方法排除&
和之间的匹配代码>同时仍接受包含这两个字符的序列
预期结果:
- 搜索
img边框=';0' /代码>对于lt
:不匹配
- 搜索
img边框=';0' /代码>对于39
:不匹配
- 搜索
img边框=';0' /代码>用于和#039代码>:匹配
- 搜索
img边框=';0' /代码>用于border='代码>:匹配
当前代码:
> var str = '<img border='0' />'
> str.replace(/(border)/gi, '|$1|')
'<img |border|='0' />' // ok
> str.replace(/(39)/gi, '|$1|')
'<img border=�|39|;0�|39|; />' // not ok
注意:我不能先退出,然后再重新退出以匹配。它必须被转义。我认为您指的是非捕获组:,这在一些堆栈溢出帖子(和)中得到了轻松解决
也就是说,未捕获的组没有自己的组选择器(例如/a(?[X-Z])([a-c])/g将匹配“aZb”,但\1将等于“b”,而不是“Z”。这就是您试图做的吗
var str=“img边框颜色=';0';”
console.log(str)
console.log(str.match(/((?:[a-z-]+=)?.+?)/gi))
log(str.replace(/((?:[a-z-]+=)?.+?)/gi,“|$1 |”)
这里的一个选项是在执行实际替换之前,在转义字符序列中的任何位置临时将正在搜索的字符串替换为“伪”字符串字符串必须是HTML中不太可能出现的内容。执行实际替换后,可以进行进一步替换,将“伪”字符串更改回正在搜索的字符串
下面是此方法的一个演示,它将生成所请求的结果。当需要不使用正则表达式的全局替换时,它将使用该方法,并将任何字符串转换为字符串文字以用于正则表达式(任何特殊字符都将被适当转义)
var html=“img border=';0';/”
replaceInHtml(html,'lt','replacement');
replaceInHtml(html,'39','replacement');
replaceInHtml(html,';,'replacement');
replaceInHtml(html,'border=';','replacement');
函数replaceInHtml(html、str、replacement){
//不太可能出现在HTML中的唯一字符串
变量dummyStr='!*&$^;';
var strInRegex=escapeRegExp(str);
var dummyRegex=新的RegExp(“(&[#a-zA-Z0-9]*)”
+strInRegex+'([#a-zA-Z0-9]*)','g');
var replaced=html.replace(dummyRegex,'$1'+dummyStr+'$2');
替换=替换。拆分(str)。连接(替换);
已替换=已替换.split(dummyStr).join(str);
console.log('Source:'+html
+'\n替换:'+str
+“\n带:”+替换
+“\n活动:”+已替换);
}
函数escapeRegExp(str){
返回str.replace(/[\-\[\]\/\{\\}(\)\*\+\?\.\\\^\$\\\\\\\\\\;]/g,“\$&”);
}
我从匹配&
和之间的所有内容开始;
:
let str=“39img border=39';0';&39;/39”;
让搜索='39';
设regexp=newregexp('&[^&;]*?('+search+')[^&;]*?;','g');//&[^&;]*?(search)[^&;]*?;/g
让match=str.match(regexp);
console.log(match);
我认为如果我们能够使用回溯,这是可能的。鉴于正则表达式的风格是JavaScript,我认为我们不能。这非常接近:
[^&;]*(string)[^&]*(?!9;| t;|))
应该使用正则表达式来检查这一点,但它不能覆盖所有可能的实体,并且不是此作业的最佳工具。而下面的方法将适用于所有HTML实体
我试图匹配和替换完整的转义序列,如';
,但不是部分的,如39
,因为39
实际上不在未转义字符串中
基本上,您希望用它的未定型形式替换HTML实体。下面的函数就是这么做的,您不需要正则表达式
我将从中使用unescapethtml
函数
这首先创建一个新的
元素。在函数中,作为参数传递的字符串随后被指定为此textarea的innerHTML,然后返回其textContent。这是用于取消显示HTML实体的技巧
我们可以重用它来确定字符串是否为有效的HTML实体。如果函数能够对其进行取消扫描,则它是有效的HTML实体,否则它不是。这就是您要确定的
var escape=document.createElement('textarea');
函数unescapethtml(html){
escape.innerHTML=html;
返回escape.textContent;
}
var str='img border=';0';/';
log(unescapeHTML('lt')!='lt');
log(unescapeHTML('39')!='39');
log(unescapeHTML('';')!='';');
log(unescapeHTML('border=';')!='border=';');
最终候选版本
4/29
此版本应处理搜索字符串末尾的部分实体
其中,部分具有前实体字符,如xxx&yyy
或a
等
这是@TomasLangkaas发现的最后一个病例。
鉴于涵盖了所有其他案例,这是最终版本候选
为@Athanchahill或其他感兴趣的人
(参见注释和以前的版本)
模型已从String.Replace()更改为while(match=Rx.exec())
此处解释,但请参见JS代码以了解实现。
它仍然使用搜索字符串作为第一个替代项
以实体作为第二个
(?=
# This is the optional entity captured at
# the same position where the search string starts.
# If this entity matches, it means the search string
# matches. Either one may be a partial of the other.
# (1) The container for pre-entity / entity
(
# (2) Pre-entity characters
( sLongest )
# Entity
(?:&(?:[a-z_:][a-zd_:.-]*|(?:\#(?:[0-9]+|x[0-9a-f]+)))|%[a-z_:][a-zd_:.-]*);
)?
)
# (3) The search string ( consumes )
( sToFind )
|
# (4) Or, the entity last ( consumes )
( (?:&(?:[a-z_:][a-zd_:.-]*|(?:\#(?:[0-9]+|x[0-9a-f]+)))|%[a-z_:][a-zd_:.-]*); )
请注意,不能将实体语法分解为正则表达式的一部分。
它必须完全匹配,作为一个独特的
(?=
# This is the optional entity captured at
# the same position where the search string starts.
# If this entity matches, it means the search string
# matches. Either one may be a partial of the other.
# (1) The container for pre-entity / entity
(
# (2) Pre-entity characters
( sLongest )
# Entity
(?:&(?:[a-z_:][a-zd_:.-]*|(?:\#(?:[0-9]+|x[0-9a-f]+)))|%[a-z_:][a-zd_:.-]*);
)?
)
# (3) The search string ( consumes )
( sToFind )
|
# (4) Or, the entity last ( consumes )
( (?:&(?:[a-z_:][a-zd_:.-]*|(?:\#(?:[0-9]+|x[0-9a-f]+)))|%[a-z_:][a-zd_:.-]*); )
function do_replace(test_str, find_str, replace_str) {
let escaped_find_str = AmpExcape(find_str);
escaped_find_str = RegExcape(escaped_find_str);
let escaped_replace_str = RegExcape(replace_str);
let first_regex = new RegExp('(' + escaped_find_str + ')|(&\\w*;|&#[0-9a-fA-F]*;)','gi');
let first_pass = test_str.replace(first_regex,'&&$1'+replace_str+'&&$2');
let second_regex = new RegExp('&&(?:'+escaped_replace_str+'&&|(' + escaped_find_str + ')?('+escaped_replace_str + ')?&&)','gi');
let second_pass = first_pass.replace(second_regex,'$2');
return second_pass;
}
&&<target group value><replacement string>&&<entity group value>
// helper for building regexes from strings
// http://stackoverflow.com/a/3561711/6738706
function AmpExcape(str) {
return str.replace(/&(\w*;|#[0-9a-fA-F]*;)|(&)/g, '&$2$1');
}
function RegExcape(str) {
return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
};
function do_replace(test_str, find_str, replace_str) {
let escaped_find_str = AmpExcape(find_str);
escaped_find_str = RegExcape(escaped_find_str);
let escaped_replace_str = RegExcape(replace_str);
let first_regex = new RegExp('(' + escaped_find_str + ')|(&\\w*;|&#[0-9a-fA-F]*;)','gi');
let first_pass = test_str.replace(first_regex,'&&$1'+replace_str+'&&$2');
let second_regex = new RegExp('&&(?:'+escaped_replace_str+'&&|(' + escaped_find_str + ')?('+escaped_replace_str + ')?&&)','gi');
let second_pass = first_pass.replace(second_regex,'$2');
return second_pass;
}
let str = '39<img style='width: 39;' bor9;wder=39'0'&39; />39;';
let test_list = ['39','39;','9;','9;w','39&','0&#'];
run_test(str,test_list);
str = '<img border='0' /$gt;';
test_list = ['lt','39',''','border=''];
run_test(str,test_list);
str = 'test string ring ring';
test_list = ['ring'];
run_test(str,test_list);
str = '39<img style='width: 39;' border='0'&39; />39;';
test_list = ['border','0',''','39','lt','<','border='','<img','&g','t;'];
run_test(str,test_list);
function run_test(base_str, find_list) {
let orig_str = 'original';
let max_len = find_list.concat(orig_str).reduce(function(a,b) {
return a > b.length ? a : b.length;
},0);
console.log();
console.log(pad(orig_str,max_len) + ': ' + str);
find_list.map(function(gstr) {
console.log( pad( gstr, max_len) + ': ' + do_replace(str, gstr, '|' + gstr + '|'));
});
}
function pad(str,len) {
while ( str.length < len) { str = str + ' ' };
return str;
}
original: 39<img style='width: 39;' bor9;wder=39'0'&39; />39;
39 : |39|<img style='width: |39|;' bor9;wder=|39|'0'&39; />|39|;
39; : 39<img style='width: |39;|' bor9;wder=39'0'&39; />|39;|
9; : 39<img style='width: 3|9;|' bor|9;|wder=39'0'&39; />3|9;|
9;w : 39<img style='width: 39;' bor|9;w|der=39'0'&39; />39;
39& : 39<img style='width: 39;' bor9;wder=39'0'&39; />39;
0&# : 39<img style='width: 39;' bor9;wder=39'0'&39; />39;
original : <img border='0' /$gt;
lt : <img border='0' /$gt;
39 : <img border='0' /$gt;
' : <img border=|'|0|'| /$gt;
border=': <img |border='|0' /$gt;
original: test string ring ring
ring : test st|ring| |ring| |ring|
original : 39<img style='width: 39;' border='0'&39; />39;
border : 39<img style='width: 39;' |border|='0'&39; />39;
0 : 39<img style='width: 39;' border='|0|'&39; />39;
' : 39<img style=|'|width: 39;|'| border=|'|0|'|&39; />39;
39 : |39|<img style='width: |39|;' border='0'&39; />|39|;
lt : 39<img style='width: 39;' border='0'&39; />39;
< : 39|<|img style='width: 39;' border='0'&39; />39;
border=': 39<img style='width: 39;' |border='|0'&39; />39;
<img : 39|<img| style='width: 39;' border='0'&39; />39;
&g : 39<img style='width: 39;' border='0'&39; />39;
t; : 39<img style='width: 39;' border='0'&39; />39;
'((?:^|(?!(?:[^&;]+' + str + ')))(?=(?:(?:&|;|^)[^&;]*))(?:(?!(?:&))(?:(?:^|[;]?)[^&;]*?))?)(' + str + ')'
"original": <img border='0' /$gt;
"lt": <img border='0' /$gt;
"39": <img border='0' /$gt;
"'": <img border=|'|0|'| /$gt;
"border='": <img |border='|0' /$gt;
"original": 39<img style='width: 39;' bor;der=39'0'&39; />39;
test string that may be followed by semi-colon :
|39|<img style='width: |39|;' bor;der=|39|'0'&39; />|39|;
test match with semi-colon:
39<img style='width: |39;|' bor;der=39'0'&39; />|39;|
test match with semi-colon mid string
39<img style='width: 39;' |bor;der|=39'0'&39; />39;
"original": test string ring ring
test st|ring| ring ring
function make_regex(str) {
let regexp = new RegExp('((?:^|(?!(?:[^&;]+' + str + ')))(?=(?:(?:&|;|^)[^&;]*))(?:(?!(?:&))(?:(?:^|[;]?)[^&;]*?))?)(' + str + ')','gi');
return regexp;
}
function do_replace(test_str, find_str, replace_str) {
let new_reg = make_regex(find_str);
return test_str.replace(new_reg,'$1' + replace_str);
}
let str = '39<img style='width: 39;' bor;der=39'0'&39; />39;';
console.log();
console.log('"original": ', str);
console.log('test string that may be followed by semi-colon :');
console.log(do_replace(str, '39', '|$2|' ));
console.log('test match with semi-colon:');
console.log(do_replace(str, '39;', '|39;|' ));
console.log('test match with semi-colon mid string');
console.log(do_replace(str, 'bor;der', '|bor;der|' ))
str = '<img border='0' /$gt;';
console.log();
console.log('"original": ', str);
console.log('"lt": ', do_replace(str, 'lt', '|lt|' ));
console.log('"39": ', do_replace(str, '39', '|39|' ));
console.log('"'": ', do_replace(str, ''', '|'|' ));
console.log('"border='":', do_replace(str, 'border='', '|border='|' ));
str = 'test string ring ring';
console.log();
console.log('"original": ', str);
console.log(do_replace(str, 'ring', '|$2|'));
(?:^|(?!(?:[^&;]+' + str + ')))
(?=(?:(?:&|;|^)[^&;]*))
(?:(?!(?:&))(?:(?:^|[;]?)[^&;]*?))?
str.replace(
/(&[a-z]+;|&#[0-9a-f]+;)|39/gi,
function(m, entity){
return entity || replacement;
}
);
/&[a-z]+;|&#x[a-f\d]+;|&#\d+;/gi
function searchAndReplace(searchFor, replacement, str) {
return str.replace(
new RegExp(
prepare(searchFor) +
"|(&[a-z]+;|&#x[a-f\\d]+;|&#\\d+;)", // consume entities
"gi"
),
function(m, entity) {
return entity || replacement;
}
);
}
function prepare(str) {
return str.replace(/[^\w\s]/g, "\\$&"); //escape regex metachars [1]
}
// [1] from http://eloquentjavascript.net/09_regexp.html#h_Rhu25fogrG