8

我有正则表达式的问题。除了一组指定的单词,我需要制作正则表达式,例如:apple、orange、juice。并且给定这些词,它将匹配除上面那些词之外的所有内容。

applejuice (match)
yummyjuice (match)
yummy-apple-juice (match)
orangeapplejuice (match)
orange-apple-juice (match)
apple-orange-aple (match)
juice-juice-juice (match)
orange-juice (match)

apple (should not match)
orange (should not match)
juice (should not match)
4

6 回答 6

10

如果您真的想使用单个正则表达式执行此操作,您可能会发现环视很有帮助(尤其是本示例中的负前瞻)。为 Ruby 编写的正则表达式(某些实现具有不同的环视语法):

rx = /^(?!apple$|orange$|juice$)/
于 2009-12-01T13:23:12.700 回答
3

我注意到apple-juice应该根据您的参数匹配,但是呢apple juice?我假设如果你正在验证apple juice你仍然希望它失败。

所以 - 让我们构建一组算作“边界”的字符:

/[^-a-z0-9A-Z_]/        // Will match any character that is <NOT> - _ or 
                        // between a-z 0-9 A-Z 

/(?:^|[^-a-z0-9A-Z_])/  // Matches the beginning of the string, or one of those 
                        // non-word characters.

/(?:[^-a-z0-9A-Z_]|$)/  // Matches a non-word or the end of string

/(?:^|[^-a-z0-9A-Z_])(apple|orange|juice)(?:[^-a-z0-9A-Z_]|$)/ 
   // This should >match< apple/orange/juice ONLY when not preceded/followed by another
   // 'non-word' character just negate the result of the test to obtain your desired
   // result.

在大多数正则表达式风格中,都\b算作“单词边界”,但“单词字符”的标准列表不包括在内-,因此您需要创建一个自定义列表。/\b(apple|orange|juice)\b/如果你不试图抓住它,它可能会匹配-......

如果您只测试“单字”测试,您可以使用更简单的方法:

/^(apple|orange|juice)$/ // and take the negation of this...
于 2009-12-01T13:33:21.937 回答
0
\A(?!apple\Z|juice\Z|orange\Z).*\Z

将匹配整个字符串,除非它只包含一个禁用词。

或者,如果您没有使用 Ruby,或者您确定您的字符串不包含换行符,或者您设置了^$行首/行尾不匹配的选项

^(?!apple$|juice$|orange$).*$

也将工作。

于 2009-12-01T15:30:37.810 回答
0

这得到了一些方式:

((?:apple|orange|juice)\S)|(\S(?:apple|orange|juice))|(\S(?:apple|orange|juice)\S)
于 2009-12-01T14:37:02.587 回答
0

这里有一些简单的复制粘贴代码,它不仅仅适用于确切的单词异常。


复制/粘贴代码:

在以下正则表达式中,仅用您的正则表达式替换全部大写部分。

Python 正则表达式
pattern = r"REGEX_BEFORE(?>(?P<exceptions_group_1>EXCEPTION_PATTERN)|YOUR_NORMAL_PATTERN)(?(exceptions_group_1)always(?<=fail)|)REGEX_AFTER"
红宝石正则表达式
pattern = /REGEX_BEFORE(?>(?<exceptions_group_1>EXCEPTION_PATTERN)|YOUR_NORMAL_PATTERN)(?(<exceptions_group_1>)always(?<=fail)|)REGEX_AFTER/
PCRE正则表达式
REGEX_BEFORE(?>(?<exceptions_group_1>EXCEPTION_PATTERN)|YOUR_NORMAL_PATTERN)(?(exceptions_group_1)always(?<=fail)|)REGEX_AFTER
JavaScript

截至 2020 年 6 月 17 日,这是不可能的,而且在不久的将来可能也不可能。



完整示例

REGEX_BEFORE = \b
YOUR_NORMAL_PATTERN = \w+
REGEX_AFTER =
EXCEPTION_PATTERN = (苹果|橙子|果汁)

Python 正则表达式
pattern = r"\b(?>(?P<exceptions_group_1>(apple|orange|juice))|\w+)(?(exceptions_group_1)always(?<=fail)|)"
红宝石正则表达式
pattern = /\b(?>(?<exceptions_group_1>(apple|orange|juice))|\w+)(?(<exceptions_group_1>)always(?<=fail)|)/
PCRE正则表达式
\b(?>(?<exceptions_group_1>(apple|orange|juice))|\w+)(?(exceptions_group_1)always(?<=fail)|)



它是如何工作的?

这使用了相当复杂的正则表达式,即原子组、条件、Lookbehinds 和命名组。

  1. (?>是一个原子组的开始,这意味着它不允许回溯:这意味着,如果该组匹配一次,但后来因为后向失败而失效,那么整个组将无法匹配。(在这种情况下我们想要这种行为)。

  2. (?<exceptions_group_1>创建一个命名的捕获组。它比使用数字更容易。请注意,该模式首先尝试查找异常,然后如果找不到异常,则回退到正常模式。

  3. 请注意,原子模式首先尝试查找异常,然后如果找不到异常则回退到正常模式。

  4. 真正的魔力在(?(exceptions_group_1). 这是一个询问 exceptions_group_1 是否成功匹配的条件。如果是,那么它会尝试查找always(?<=fail). 这种模式(正如它所说的)总是会失败,因为它会寻找“always”这个词,然后它会检查“does "ways"=="fail"',但它永远不会。

  5. 因为条件失败,这意味着原子组失败,并且因为它是原子的,这意味着它不允许回溯(试图寻找正常模式),因为它已经匹配了异常。

这绝对不是这些工具的预期用途,但它应该可靠且高效地工作。



Ruby中原始问题的确切答案

/\b(?>(?<exceptions_group_1>(apple|orange|juice))|\w+)(?(<exceptions_group_1>)always(?<=fail)|)/

与其他方法不同,可以修改此方法以拒绝任何模式,例如任何不包含子字符串“apple”、“orange”或“juice”的单词。

/\b(?>(?<exceptions_group_1>\w*(apple|orange|juice))|\w+)(?(<exceptions_group_1>)always(?<=fail)|)/
于 2020-06-17T21:27:18.903 回答
-1

类似(PHP)的东西

$input = "The orange apple gave juice";
if(preg_match("your regex for validating") && !preg_match("/apple|orange|juice/", $input))
{
  // it's ok;
}
else
{
  //throw validation error
}
于 2009-12-01T13:10:53.183 回答