【问题标题】:How to conditional regex如何条件正则表达式
【发布时间】:2011-07-24 02:26:00
【问题描述】:

我想要一个正则表达式,如果它在字符串中有 3 个 . 实例,它会做一件事,如果它有超过 3 个实例,它会做其他事情。

例如

aaa.bbb.ccc.ddd // one part of the regex

aaa.bbb.ccc.ddd.eee // the second part of the regex

如何在jsc# 中实现这一点?

类似

?(\.){4} then THIS else THAT

在正则表达式中...

更新

好吧,基本上我正在做的是这样的:

对于任何给定的System.Uri,我想在扩展方法中切换到另一个子域。

我遇到的问题是我的域通常是http://subdomain.domain.TLD.TLD/more/url 的形式,但有时它可能只是http://domain.TLD.TLD/more/url(它只是指向www

这就是我想出的:

public static class UriExtensions
{
    private const string TopLevelDomainRegex = @"(\.[^\.]{2,3}|\.[^\.]{2,3}\.[^\.]{2,3})$";
    private const string UnspecifiedSubdomainRegex = @"^((http[s]?|ftp):\/\/)(()([^:\/\s]+))(:([^\/]*))?((?:\/)?|(?:\/)(((\w+)*\/)([\w\-\.]+[^#?\s]+)(\?([^#]*))?(#(.*))?))?$";
    private const string SpecifiedSubdomainRegex = @"^((http[s]?|ftp):\/\/)(([^.:\/\s]*)[\.]([^:\/\s]+))(:([^\/]*))?((?:\/)?|(?:\/)(((\w+)*\/)([\w\-\.]+[^#?\s]+)(\?([^#]*))?(#(.*))?))?$";

    public static string AbsolutePathToSubdomain(this Uri uri, string subdomain)
    {
        subdomain = subdomain == "www" ? string.Empty : string.Concat(subdomain, ".");

        var replacement = "$1{0}$5$6".FormatWith(subdomain);

        var spec = Regex.Replace(uri.Authority, TopLevelDomainRegex, string.Empty).Distinct().Count(c => c == '.') != 0;
        return Regex.Replace(uri.AbsoluteUri, spec ? SpecifiedSubdomainRegex : UnspecifiedSubdomainRegex, replacement);
    }
}

基本上使用此代码,我采用System.Uri 和:

  1. 使用Authority 属性仅获取subdomain.domain.TLD.TLD
  2. 将其与“伪 TLD”相匹配(我永远不会拥有一个包含 2-3 个字母的注册域会破坏正则表达式,它基本上会检查以 .XX[X].XX[X].XX[X] 结尾的任何内容)
  3. 我剥离了 TLD,最终得到 domainsubdomain.domain
  4. 如果结果数据有零个点,我使用UnspecifiedSubdomainRegex,因为我不知道如何使用SpecifiedSubdomainRegex 告诉它如果该部分没有点,它应该返回string.Empty

我的问题是,是否有办法将这三个正则表达式合并成更简单的东西

PD:忘掉javascript吧,我只是用它来测试正则表达式

【问题讨论】:

  • 注意:在绝大多数情况下,要求条件正则表达式的人并不真正需要它。通常可以通过使用更简单的结构来避免它,例如交替和可选组。当然,您必须提供更多详细信息,即:“does”、“one thing”、“something else”、“THIS else THAT”和预期输出。

标签: c# regex


【解决方案1】:

您可以使用(?(?=condition)then|else) 构造来做到这一点。但是,这在 JavaScript 中不可用(但在 .NET、Perl 和 PCRE 中可用):

^(?(?=(?:[^.]*\.){3}[^.]*$)aaa|eee)

例如,将检查一个字符串是否正好包含三个点,如果是,它会尝试匹配字符串开头的aaa;否则它会尝试匹配eee。所以它会匹配

的前三个字母
aaa.bbb.ccc.ddd
eee.ddd.ccc.bbb.aaa
eee

但失败了

aaa.bbb.ccc
eee.ddd.ccc.bbb
aaa.bbb.ccc.ddd.eee

说明:

^            # Start of string
(?           # Conditional: If the following lookahead succeeds:
 (?=         #   Positive lookahead - can we match...
  (?:        #     the following group, consisting of
   [^.]*\.   #     0+ non-dots and 1 dot
  ){3}       #     3 times
  [^.]*      #     followed only by non-dots...
  $          #     until end-of-string?
 )           #   End of lookahead
 aaa         # Then try to match aaa
|            # else...
 eee         # try to match eee
)            # End of conditional

【讨论】:

  • 天啊,我误读了他的问题。我虽然他需要根据正则表达式执行不同的操作。 +1 给你。
  • 在 Javascript 中模拟条件:(?:(?=condition)aaa|(?!condition)eee)
  • @MarkusJarderot 虽然这只适用于简单的情况,但它绝对很棒!非常感谢!我现在在 Oniguruma-flavor RE 中使用它。
  • @MarkusJarderot condition 这里是must be of fixed length
  • 感谢蒂姆的出色回答,非常感谢!
【解决方案2】:
^(?:[^.]*\.[^.]*){3}$

上面的正则表达式将匹配恰好有 3 个点的字符串 --- http://rubular.com/r/Tsaemvz1Yi

^(?:[^.]*\.[^.]*){4,}$

还有这个 - 对于有 4 个或更多点的字符串 --- http://rubular.com/r/IJDeQWVhEB

【讨论】:

  • 我如何在条件下使用它?我想“如果这个正则表达式匹配,那么使用这个正则表达式,否则使用这个其他正则表达式”
  • @Nico:正则表达式本身只是一个字符串文字。如果不使用特殊函数或运算符,它就不能做任何事情,例如“Hello world”字符串在你打印之前不能做任何事情。
  • 我知道,但是我读过一些关于?()?= 条件的东西,似乎这种事情可以用正则表达式完成
  • @zerkms:嗯,这正是条件正则表达式的用途。但它们在 JavaScript 中不存在。
【解决方案3】:

在 Python 中(对不起;但正则表达式没有语言边界)

import re

regx = re.compile('^([^.]*?\.){3}[^.]*?\.')

for ss in ("aaa.bbb.ccc",
           "aaa.bbb.ccc.ddd",
           'aaa.bbb.ccc.ddd.eee',
           'a.b.c.d.e.f.g.h.i...'):
  if regx.search(ss):
    print ss + '     has at least 4 dots in it'
  else:
    print ss + '     has a maximum of 3 dots in it'

结果

aaa.bbb.ccc     has a maximum of 3 dots in it
aaa.bbb.ccc.ddd     has a maximum of 3 dots in it
aaa.bbb.ccc.ddd.eee     has at least 4 dots in it
a.b.c.d.e.f.g.h.i...     has at least 4 dots in it

此正则表达式模式不需要分析整个字符串(其中没有符号 $)。长字符串效果更好。

【讨论】:

    【解决方案4】:

    你不需要正则表达式来做这个(对于许多其他常见任务)。

    public static string AbsolutePathToSubdomain(this Uri uri, string subdomain)
    {
        // Pre-process the new subdomain
        if (subdomain == null || subdomain.Equals("www", StringComparison.CurrentCultureIgnoreCase))
            subdomain = string.Empty;
    
        // Count number of TLDs (assume at least one)
        List<string> parts = uri.Host.Split('.').ToList();
        int tldCount = 1;
        if (parts.Count >= 2 && parts[parts.Count - 2].Length <= 3)
        {
            tldCount++;
        }
    
        // Drop all subdomains
        if (parts.Count - tldCount > 1)
            parts.RemoveRange(0, parts.Count - tldCount - 1);
    
        // Add new subdomain, if applicable
        if (subdomain != string.Empty)
            parts.Insert(0, subdomain);
    
        // Construct the new URI
        UriBuilder builder = new UriBuilder(uri);
        builder.Host = string.Join(".", parts.ToArray());
        builder.Path = "/";
        builder.Query = "";
        builder.Fragment = "";
    
        return builder.Uri.ToString();
    }
    

    【讨论】:

      猜你喜欢
      • 2011-10-30
      • 2016-09-19
      • 1970-01-01
      • 2022-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多