Javascript正则表达式:匹配任何东西,直到某个东西(如果存在)

26

我对正则表达式不熟悉,这可能是一个非常简单的问题(希望如此)。

我正在尝试使用一种解决方案来处理三种类型的字符串

  • "45%",期望结果:“45”
  • "45",期望结果:“45”
  • "",期望结果:“”

我的尝试(假设字符串为str):

str.match(/(.*)(?!%*)/i)[1]

我的理解是,匹配任何一段文本,直到找到 '%',如果找到就停止匹配,并且匹配结果不包含 '%'; 如果没有找到 '%',则匹配整个文本。

在 Firebug 中,它的意思似乎更像是“匹配整个文本并完全忽略负向先行断言”。另外,使用非贪婪模式 - (.*)? - 似乎也没有帮助。

先不考虑我这种情况只匹配数字的特殊情况,那么一个/\d*/ 就可以了。我想理解一个通用的规则,以便在需要时应用它。

请问有人能帮帮我吗?


1
负向先行断言:(?!%*) 表示:“断言零个或多个百分号不会跟随其后”。这种断言永远不可能成立,因为 %* 总是为真! (%* 不匹配任何内容 - 这在任何地方都是 始终 为真的 - 即使对于空字符串也是如此。) - ridgerunner
5个回答

42

简单点怎么样

str.match(/[^%]*/i)[0]
这意味着匹配零或多个不是%的字符。

编辑:如果需要解析直到</a>,那么您可以解析一个字符序列,后面跟随</a>,然后丢弃</a>,这意味着您应该使用正向先行断言而不是负向先行断言。

str.match(/.*?(?=<\/a>|$)/i)[0]
这意味着:进行零个或多个字符的懒惰匹配,直到遇到</a>标记或字符串结尾为止。
请注意,*?是一个单一运算符,(.*)?.*?不同。
(而且通常情况下,请勿使用单个正则表达式解析HTML,详见此处。)

在正则表达式中,特别是JavaScript风格的正则表达式中,^字符表示从参考字符串的开头开始匹配。https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions - austincheney
@austincheney:当^用作文本锚点时,这是正确的,但是当在字符类中使用^时,它具有不同的含义,即否定匹配(“除了这些字符之外的任何东西…”)。 - bobbymcr
谢谢Kenny,这个可行。但如果“%”是“</a>”呢?我想要排除比单个字符更多的模式。为了让它更清楚,“</a>”(或任何模式)可能存在,也可能不存在。 - undefinederror
谢谢Kenny,这正是我所希望找到的。请看我的回复Alan的评论。此外,我非常感激你花时间一点一点地解释它……祝圣诞快乐! - undefinederror

9
我认为这是您正在寻找的内容:

我想这就是您所需要的:

/(?:(?!%).)*/
.匹配任何字符,但只有在负向前瞻(?!%)确认该字符不是%之后才匹配。请注意,当哨兵是单个字符,例如%时,您可以使用否定字符类,例如:
/[^%]*/

但对于像</a>这样的多字符标志,您必须使用前瞻方法:

/(?:(?!</a>).)*/i

这实际上是指一次匹配零个或多个字符,但如果下一个字符是序列</a></A>的开头,则停止匹配而不消耗它。

这太棒了。正是我正在寻找的。感谢你和肯尼,现在我知道如何一步一步地进行,确保我的最后一步不会落在某个模式 /((?!pattern).)*/ 上,以及如何走长路直到下一个字符是我的模式的开头或字符串的结尾 /.*?(?=pattern|$)/ 。我认为肯尼的更符合我的期望,而你的则不那么明显,绝对是个好主意。我不认为我会想到这个。谢谢! - undefinederror

3

如果要进行准确搜索,最简单的方法是跳过正则表达式,直接使用 indexOf 函数,例如:

// String to be searched
var s = "Here is a <a>link</a>."

// String to find
var searchString = "</a>";

// Final match
var matched = "";

var c = s.indexOf(searchString);
if (c >= 0)
{
    // Returns the portion not including the search string;
    // in this example, "Here is a <a>link". If you want the
    // search string included, add the length of the search
    // string to c.
    matched = s.substring(c);
}

2
谢谢Bobby,但我正在寻找一个正则表达式的解决方案。你所描述的是我通常会做的事情,但这样做我最终会反复使用我的词汇库。 - undefinederror

1

我刚刚按照你说的话写了它:

str.match(/(^[^%]*$)|^([^%]*)%.*/i)

这将匹配任何不含有“%”的字符串或者第一个包含“%”的字符串。

你需要从第一组或第二组中获取结果。

编辑:下面是您想要的内容。

str.match(/(?:^[^%]*$)|^(?:[^%]*)(?=%)/)
  • ?: 去除所有分组
  • ?= 是一个前瞻,用于查看字符串是否包含 %
  • [^%] 匹配任何不是 % 的字符

因此,正则表达式的意思是匹配任何不包含 % 的字符串,或者(否则匹配)第一个 % 之前的所有字符。


0

要匹配45、45%和任意长度的任何数字,请使用以下内容(182%、18242等)

str.match(/([0-9]+)([%]?)/)[1];

如果您需要匹配空字符串,也请将其包含为^$,请注意match("...")[1] 对于空字符串将未定义,因此您需要测试匹配,然后检查[0]或查看[1]是否未定义。

str.match(/([0-9]+)([%]?)|^$/)

如果您需要精确匹配两个数字,请使用{2,2}锚定表达式在开头和结尾行字符之间:" ^(exp)$"

str.match(/^([0-9]{2,2})([%]?)$/)[1];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接