Regular expression to select all whitespace that i

2019-02-01 23:44发布

I'm not very good at RegEx, can someone give me a regex (to use in Java) that will select all whitespace that isn't between two quotes? I am trying to remove all such whitespace from a string, so any solution to do so will work.

For example:

(this is a test "sentence for the regex")

should become

(thisisatest"sentence for the regex")

7条回答
相关推荐>>
2楼-- · 2019-02-01 23:50

I have absolutely no idea how the top voted answer works and the regex is huge, so I'm submitting this somewhat simpler answer:

\s+(?=(?:'(?:\\'|[^'])+'|[^'])+$)

It (in theory) works by using a lookahead match to ensure single quotes (') are balanced all the way to the end of the string before testing to see if the whitespace is a valid place to break.

This image shows it executing, and it does, but pretty slowly. As other answers will likely have noted, using such an expression to split a potentially quoted string is using a hammer to remove a rivet. In my case, I'm inputting this regex to a program that takes a regex to split on (fzf).

查看更多
对你真心纯属浪费
3楼-- · 2019-02-01 23:54

This just isn't something regexes are good at. Search-and-replace functions with regexes are always a bit limited, and any sort of nesting/containment at all becomes difficult and/or impossible.

I'd suggest an alternate approach: Split your string on quote characters. Go through the resulting array of strings, and strip the spaces from every other substring (whether you start with the first or second depends on whether you string started with a quote or not). Then join them back together, using quotes as separators. That should produce the results you're looking for.

Hope that helps!

PS: Note that this won't handle nested strings, but since you can't make nested strings with the ASCII double-qutoe character, I'm gonna assume you don't need that behaviour.

PPS: Once you're dealing with your substrings, then it's a good time to use regexes to kill those spaces - no containing quotes to worry about. Just remember to use the /.../g modifier to make sure it's a global replacement and not just the first match.

查看更多
乱世女痞
4楼-- · 2019-02-02 00:06

Groups of whitespace outside of quotes are separated by stuff that's a) not whitespace, or b) inside quotes.

Perhaps something like:

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

The first part matches a sequence of spaces; the second part matches non-spaces (and non-quotes), or some stuff in quotes, either repeated any number of times. The second part is the separator.

This will give you two groups for each item in the result; just ignore the second element. (We need the parentheses for precidence rather than match grouping there.) Or, you could say, concatenate all the second elements -- though you need to match the first non-space word too, or in this example, make the spaces optional:

StringBuffer b = new StringBuffer();
Pattern p = Pattern.compile("(\\s+)?([^ \"]+|\"[^\"]*\")*");
Matcher m = p.matcher("this is \"a test\"");
while (m.find()) {
    if (m.group(2) != null)
        b.append(m.group(2));
}
System.out.println(b.toString());

(I haven't done much regex in Java so expect bugs.)

Finally This is how I'd do it if regexes were compulsory. ;-)

As well as Xavier's technique, you could simply do it the way you'd do it in C: just iterate over the input characters, and copy each to the new string if either it's non-space, or you've counted an odd number of quotes up to that point.

查看更多
爷、活的狠高调
5楼-- · 2019-02-02 00:07

Here's a single regex-replace that works:

\s+(?=([^"]*"[^"]*")*[^"]*$)

which will replace:

(this is a test "sentence for the regex" foo bar)

with:

(thisisatest"sentence for the regex"foobar)

Note that if the quotes can be escaped, the even more verbose regex will do the trick:

\s+(?=((\\[\\"]|[^\\"])*"(\\[\\"]|[^\\"])*")*(\\[\\"]|[^\\"])*$)

which replaces the input:

(this is a test "sentence \"for the regex" foo bar)

with:

(thisisatest"sentence \"for the regex"foobar)

(note that it also works with escaped backspaces: (thisisatest"sentence \\\"for the regex"foobar))

Needless to say (?), this really shouldn't be used to perform such a task: it makes ones eyes bleed, and it performs its task in quadratic time, while a simple linear solution exists.

EDIT

A quick demo:

String text = "(this is a test \"sentence \\\"for the regex\" foo bar)";
String regex = "\\s+(?=((\\\\[\\\\\"]|[^\\\\\"])*\"(\\\\[\\\\\"]|[^\\\\\"])*\")*(\\\\[\\\\\"]|[^\\\\\"])*$)";
System.out.println(text.replaceAll(regex, ""));

// output: (thisisatest"sentence \"for the regex"foobar)
查看更多
你好瞎i
6楼-- · 2019-02-02 00:11

Here is the regex which works for both single & double quotes (assuming that all strings are delimited properly)

\s+(?=(?:[^\'"]*[\'"][^\'"]*[\'"])*[^\'"]*$)

It won't work with the strings which has quotes inside.

Regular expression visualization

查看更多
ゆ 、 Hurt°
7楼-- · 2019-02-02 00:14

This isn't an exact solution, but you can accomplish your goal by doing the following:

STEP 1: Match the two segments

\\(([a-zA-Z ]\*)"([a-zA-Z ]\*)"\\)

STEP 2: remove spaces

temp = $1 replace " " with ""

STEP 3: rebuild your string

(temp"$2")
查看更多
登录 后发表回答