如何有条件的正则表达式
我想要一个正则表达式做一件事,如果它有3个实例.
在字符串中,如果它有超过3个实例,则为其他内容。
例如
aaa.bbb.ccc.ddd // one part of the regex aaa.bbb.ccc.ddd.eee // the second part of the regex
我如何在js
或c#
实现这一目标?
就像是
?(\.){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
和:
- 使用
Authority
属性获取subdomain.domain.TLD.TLD
。 - 将它与“伪TLD”相匹配(我永远不会有一个2-3字母的注册域会破坏正则表达式,它基本上会检查以
.XX[X]
或.XX[X].XX[X]
结尾的任何内容。.XX[X].XX[X]
) - 我剥离了TLD,最终得到了
domain
或subdomain.domain
domain
subdomain.domain
- 如果结果数据为零点,我使用
UnspecifiedSubdomainRegex
,因为我无法弄清楚如何使用SpecifiedSubdomainRegex
告诉它如果它在该部分没有点,它应该返回string.Empty
那么我的问题是,是否有办法将这三个正则表达式合并为更简单的东西
PD:忘了javascript,我只是用它来动态测试正则表达式
您可以使用(?(?=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
^(?:[^.]*\.[^.]*){3}$
上面的正则表达式将匹配正好有3个点的字符串— http://rubular.com/r/Tsaemvz1Yi 。
^(?:[^.]*\.[^.]*){4,}$
这一个 – 对于有4个点或更多点的字符串— http://rubular.com/r/IJDeQWVhEB
在Python中(对不起;但正则表达式没有语言边界)
import re regx = re.compile('^([^.]*?\.){3}[^.]*?\.') for ss in ("aaa.bbb.ccc", "aaa.bbb.ccc.ddd", 'aaa.bbb.ccc.ddd.eee', 'abcdefghi..'): 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 abcdefghi.. has at least 4 dots in it
这个正则表达式模式不要求分析整个字符串(其中没有符号$)。 在长弦上更好。
你不需要Regex(和许多其他常见任务一样)。
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 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(); }