正则expression式用于在不包含单引号或双引号时使用空格分割string

我是新来的正则expression式,并希望你的帮助。 我试图放在一起的expression式将使用不包含单引号或双引号的所有空格拆分示例string。 我的最后一次尝试看起来像这样:( (?!") ,并不是很有效,它正在引用之前的空间分裂。

示例input:

 This is a string that "will be" highlighted when your 'regular expression' matches something. 

期望的输出:

 This is a string that will be highlighted when your regular expression matches something. 

请注意, "will be"'regular expression'保留单词之间的空格。

我不明白为什么所有其他人都提出这样复杂的正则expression式或长码。 从本质上说,你想从string中获取两种东西:不是空格或者引号的字符序列,以及两个引号之间以两个引号开头和结尾的字符序列。 你可以很容易地用这个正则expression式匹配这些东西:

 [^\s"']+|"([^"]*)"|'([^']*)' 

我添加了捕获组,因为您不需要列表中的引号。

这个Java代码构build了列表,如果匹配的话添加捕获组以排除引号,并且如果捕获组不匹配(未匹配的单词匹配)则添加整体正则expression式匹配。

 List<String> matchList = new ArrayList<String>(); Pattern regex = Pattern.compile("[^\\s\"']+|\"([^\"]*)\"|'([^']*)'"); Matcher regexMatcher = regex.matcher(subjectString); while (regexMatcher.find()) { if (regexMatcher.group(1) != null) { // Add double-quoted string without the quotes matchList.add(regexMatcher.group(1)); } else if (regexMatcher.group(2) != null) { // Add single-quoted string without the quotes matchList.add(regexMatcher.group(2)); } else { // Add unquoted word matchList.add(regexMatcher.group()); } } 

如果您不介意在返回列表中有引号,则可以使用更简单的代码:

 List<String> matchList = new ArrayList<String>(); Pattern regex = Pattern.compile("[^\\s\"']+|\"[^\"]*\"|'[^']*'"); Matcher regexMatcher = regex.matcher(subjectString); while (regexMatcher.find()) { matchList.add(regexMatcher.group()); } 

有几个关于StackOverflow的问题,在使用正则expression式的各种上下文中都覆盖了这个问题。 例如:

  • parsingstring:提取单词和短语
  • parsing空间分隔文本的最佳方法

更新 :示例正则expression式来处理单引号和双引号的string。 参考: 除了在引号内时,我怎样才能在string上分割?

 m/('.*?'|".*?"|\S+)/g 

用一个快速的Perl代码片段testing了它,输出如下。 也适用于空string或空白string,如果他们之间的引号(不知道是否需要或不)。

 This is a string that "will be" highlighted when your 'regular expression' matches something. 

请注意,这包括匹配值中的引号字符本身,尽pipe可以使用stringreplace来删除引号字符,也可以修改正则expression式使其不包含它们。 我现在将这个作为一个读者或另一个海报的练习,因为凌晨2点已经太迟了,不能再搞乱正则expression式了;)

如果你想允许string中的转义引号,你可以使用像这样的东西:

 (?:(['"])(.*?)(?<!\\)(?>\\\\)*\1|([^\s]+)) 

引用的string将是组2,单引号的单词将是组3。

您可以在这里尝试各种string: http : //www.fileformat.info/tool/regex.htm或http://gskinner.com/RegExr/

Jan Goyvaerts的正则expression式是迄今为止我find的最好的解决scheme,但是也创build了空的(null)匹配,他在程序中排除了这个匹配。 这些空的匹配也出现在正则expression式testing者(例如rubular.com)。 如果你打开周围的search(首先看引用的部分,而不是空格分开的话),那么你可以做一次:

 ("[^"]*"|'[^']*'|[\S]+)+ 
 (?<!\G".{0,99999})\s|(?<=\G".{0,99999}")\s 

这将匹配未被双引号包围的空格。 我必须使用min,max {0,99999},因为Java在向后看中不支持*和+。

searchstring,抓取每个部分,分割它可能会更容易。

理由是,你可以在"will be"之前和之后的空间处分割。 但是,我想不出任何方式来指定忽略拆分内部的空间。

(不是真正的Java)

 string = "This is a string that \"will be\" highlighted when your 'regular expression' matches something."; regex = "\"(\\\"|(?!\\\").)+\"|[^ ]+"; // search for a quoted or non-spaced group final = new Array(); while (string.length > 0) { string = string.trim(); if (Regex(regex).test(string)) { final.push(Regex(regex).match(string)[0]); string = string.replace(regex, ""); // progress to next "word" } } 

另外,捕获单引号可能会导致问题:

 "Foo's Bar 'n Grill" //=> "Foo" "s Bar " "n" "Grill" 

String.split()在这里没有帮助,因为没有办法区分引号内的空格(不分割)和外部(分割)的空格。 Matcher.lookingAt()可能是你所需要的:

 String str = "This is a string that \"will be\" highlighted when your 'regular expression' matches something."; str = str + " "; // add trailing space int len = str.length(); Matcher m = Pattern.compile("((\"[^\"]+?\")|('[^']+?')|([^\\s]+?))\\s++").matcher(str); for (int i = 0; i < len; i++) { m.region(i, len); if (m.lookingAt()) { String s = m.group(1); if ((s.startsWith("\"") && s.endsWith("\"")) || (s.startsWith("'") && s.endsWith("'"))) { s = s.substring(1, s.length() - 1); } System.out.println(i + ": \"" + s + "\""); i += (m.group(0).length() - 1); } } 

产生以下输出:

 0: "This" 5: "is" 8: "a" 10: "string" 17: "that" 22: "will be" 32: "highlighted" 44: "when" 49: "your" 54: "regular expression" 75: "matches" 83: "something." 

我喜欢Marcus的方法,但是,我修改了它,以便我可以在引号附近放置文本,同时支持“和”引号字符。例如,我需要一个=“某个值”来不分割成[a =,“一些价值“]。

 (?<!\\G\\S{0,99999}[\"'].{0,99999})\\s|(?<=\\G\\S{0,99999}\".{0,99999}\"\\S{0,99999})\\s|(?<=\\G\\S{0,99999}'.{0,99999}'\\S{0,99999})\\s" 

一对夫妇希望对Jan的接受答案有所帮助:

 (['"])((?:\\\1|.)+?)\1|([^\s"']+) 
  • 允许引用string中的转义引号
  • 避免重复单引号和双引号的模式; 这也简化了如果需要添加更多的引用符号(以一个捕获组为代价)

Jan的方法很好,但是这里还有另一个logging。

如果你真的想像标题中提到的那样分割,把引号保留为"will be"'regular expression' ,那么你可以使用这种方法直接匹配(或replace)一个模式,除了情况s1,s2 ,s3等

正则expression式:

 '[^']*'|\"[^\"]*\"|( ) 

左边的两个变化匹配完整的'quoted strings'"double-quoted strings" 。 我们会忽略这些匹配。 右侧与第1组匹配并捕获空格,并且我们知道它们是正确的空格,因为它们与左侧的expression式不匹配。 我们用SplitHerereplace那些SplitHere 。 再次,这是一个真正的分裂案件,你想"will be" ,不会。

这是一个完整的工作实现(请参阅在线演示的结果)。

 import java.util.*; import java.io.*; import java.util.regex.*; import java.util.List; class Program { public static void main (String[] args) throws java.lang.Exception { String subject = "This is a string that \"will be\" highlighted when your 'regular expression' matches something."; Pattern regex = Pattern.compile("\'[^']*'|\"[^\"]*\"|( )"); Matcher m = regex.matcher(subject); StringBuffer b= new StringBuffer(); while (m.find()) { if(m.group(1) != null) m.appendReplacement(b, "SplitHere"); else m.appendReplacement(b, m.group(0)); } m.appendTail(b); String replaced = b.toString(); String[] splits = replaced.split("SplitHere"); for (String split : splits) System.out.println(split); } // end main } // end Program 

我相当肯定,这是不可能使用正则expression式。 检查其他标签内是否包含某些东西是parsing操作。 这看起来像试图parsing与正则expression式的XML相同的问题 – 它不能正确完成。 您可以通过反复应用与引用string相匹配的非贪婪的,非全局的正则expression式来获得您想要的结果,然后一旦找不到其他东西,就将其分割到空格中。问题,包括跟踪所有子串的原始顺序。 最好的办法就是写一个非常简单的函数来迭代string,并且取出你想要的标记。

你也可以试试这个:

  String str = "This is a string that \"will be\" highlighted when your 'regular expression' matches something"; String ss[] = str.split("\"|\'"); for (int i = 0; i < ss.length; i++) { if ((i % 2) == 0) {//even String[] part1 = ss[i].split(" "); for (String pp1 : part1) { System.out.println("" + pp1); } } else {//odd System.out.println("" + ss[i]); } }