【问题标题】:regexp word boundary for strings enclosed in non alnum chars非专辑字符中包含的字符串的正则表达式单词边界
【发布时间】:2017-09-08 06:40:27
【问题描述】:

我查看了有关该主题的各种帖子,但找不到满意的答案

我需要一个正则表达式来匹配像 #xxx# 这样的字符串 - 这是一个字符串,它的前后可能有不在 a-z A-Z 0-9 中的字符 - 它位于单词边界内 - 前面和后面后跟 ^ 或 $ 或不在 a-z A-Z 0-9 中的字符

我希望将其与不区分大小写和全局匹配的替换一起使用,我正在寻找以下形式的解决方案:

#xxx# 的正则表达式:

'#xxx#'.replace(regexp, 'bla') => 'bla'
'#xxx#,#xXx#)'.replace(regexp, 'bla') => 'bla,bla)'
'(#xXx#, #xxx#)'.replace(regexp, 'bla') => '(bla, bla)'

和:

'a#xxx#'.replace(regexp, 'bla') => 'a#xxx#'
'#xXx#0'.replace(regexp, 'bla') => '#xXx#0'
'hello'.replace(regexp, 'bla') => 'hello'

xxx 的正则表达式:

'xxx'.replace(regexp, 'bla') => 'bla'
'xxx,xXx)'.replace(regexp, 'bla') => 'bla,bla)'
'(xXx, xxx),'.replace(regexp, 'bla') => '(bla, bla)'

和:

'axxx'.replace(regexp, 'bla') => 'axxx'
'xXx0'.replace(regexp, 'bla') => 'xXx0'
'hello'.replace(regexp, 'bla') => 'hello'

我尝试了各种解决方案(即(?!\w)#xxx#(?!\w)),但无法正常工作。

基本上我正在寻找当字符串周围有非 alnum 字符时工作的 \b。

有什么帮助吗?

【问题讨论】:

  • 能否给出一些匹配和不匹配的测试用例?
  • 编辑了我的问题
  • 是否有一个列表列出了哪些字符可能被视为“单词”的一部分?您唯一的例子是 '#'',' 这个词的一部分,但括号不是。我觉得您没有将逗号视为单词边界有点奇怪,但无论如何...也许您可以在[^ ().-;:)]+[a-z][^ ().-;:)]+ 上匹配,即,将您认为是单词边界的所有字符列为 的字符不匹配。
  • 搜索字符串中a-zA-Z0-9之外的任何字符都是边界字符,但所有字符我们正在寻找的字符串不管它们是什么都被使用

标签: javascript regex


【解决方案1】:

不确定我是否理解正确,但将模式限制为

前后为 ^ 或 $ 或不在 a-z A-Z 0-9 中的字符

你可以使用/(^|[^0-9a-zA-Z])pattern goes here([^0-9a-zA-Z]|$)/:

  • (^|[^0-9a-zA-Z]) 将匹配字符串的开头或不在 0-9a-zA-Z 中的字符;
  • 类似([^0-9a-zA-Z]|$) 匹配字符串结尾或不在0-9a-zA-Z 中的字符;

测试用例

1) 对于#xxx#

var samples = ['#xxx#',
               '#xxx#)',
               '(#xxx#,',
               'a#xxx#',
               '#xxx#0',
               'hello']
               
console.log(
  samples.map(s => s.replace(/(^|[^0-9a-zA-Z])#xxx#([^0-9a-zA-Z]|$)/, '$1bla$2'))
)

2) 对于xxx

var samples = ['xxx',
               'xxx)',
               '(xxx,',
               'axxx',
               'xxx0', 
               'hello']
              
console.log(
  samples.map(s => s.replace(/(^|[^0-9a-zA-Z])xxx([^0-9a-zA-Z]|$)/, '$1bla$2'))
)

【讨论】:

  • 谢谢!这个解决方案对我不起作用,它还会选择两侧的标点符号(即选择#xxx#中的')'),这是我在替换中使用它时明确不想要的。
  • 如果你想提取模式,你需要捕获它。试试s.match(/(?:^|[^0-9a-zA-Z])(#xxx#)(?:[^0-9a-zA-Z]|$)) 或查看更新。
  • 我不遵循 - 这不能在正则表达式本身内完成吗? (?:[^0-9a-zA-Z]|$) 是一个 nono 捕获组,为什么它包含在结果中?
  • 这取决于你使用什么功能。以match 为例,如果模式中没有捕获组,如果匹配则返回原始字符串,因此匹配字符串和提取模式不是一回事。
  • 我想做 s.replace(regexp, 'bla') - 编辑我的问题以使其清楚
【解决方案2】:

我不确定正则表达式解决方案是否可行,我使用了这样的 javascript 解决方案:

const isAlnumChar = c => (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');

const replace = (s, f, r) => {
  const lcs = s.toLowerCase(), lcf = f.toLowerCase(), flen = f.length;
  let res = '', pos = 0, next = lcs.indexOf(lcf, pos);
  if (next === -1) return s;

  do {
    if ((next === 0 || !isAlnumChar(s[next - 1])) && (next + flen === s.length || !isAlnumChar(s[next + flen]))) {
      res += s.substring(pos, next) + r;
    } else {
      res += s.substring(pos, next + flen);
    }
    pos = next + flen;
  } while ((next = lcs.indexOf(lcf, pos)) !== -1);
  return res + s.substring(pos);
};


console.log(replace('#xxx#', '#xxx#', 'bla'));
console.log(replace('#xxx#,#xXx#)', '#xxx#', 'bla'));
console.log(replace('(#xXx#, #xxx#)', '#xxx#', 'bla'));

console.log(replace('a#xxx#', '#xxx#', 'bla'));
console.log(replace('#xXx#0', '#xxx#', 'bla'));
console.log(replace('hello', '#xxx#', 'bla'));

console.log(replace('xxx', 'xxx', 'bla'));
console.log(replace('xxx,xXx)', 'xxx', 'bla'));
console.log(replace('(xXx, xxx),', 'xxx', 'bla'));

console.log(replace('axxx', 'xxx', 'bla'));
console.log(replace('xXx0', 'xxx', 'bla'));
console.log(replace('hello', 'xxx', 'bla'));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-10
    • 1970-01-01
    • 2011-02-23
    • 1970-01-01
    相关资源
    最近更新 更多