问题
I am currently trying to learn how to use regular expressions so please bear with my simple question. For example, say I have an input file containing a bunch of links separated by a newline:
www.foo.com/Archives/monkeys.htm
Description of Monkey's website.www.foo.com/Archives/pigs.txt
Description of Pig's website.www.foo.com/Archives/kitty.txt
Description of Kitty's website.www.foo.com/Archives/apple.htm
Description of Apple's website.
If I wanted to get one website along with its description, this regex seems to work on a testing tool: .*www.*\\s.*Pig.*
However, when I try running it within my code it doesn't seem to work. Is this expression correct? I tried replacing "\s" with "\n" and it doesn't seem to work still.
回答1:
The lines are probably separated by \r\n
in your file. Both \r
(carriage return) and \n
(linefeed) are considered line-separator characters in Java regexes, and the .
metacharacter won't match either of them. \s
will match those characters, so it consumes the \r
, but that leaves .*
to match the \n
, which fails. Your tester probably used just \n
to separate the lines, which was consumed by \s
.
If I'm right, changing the \s
to \s+
or [\r\n]+
should get it to work. That's probably all you need to do in this case, but sometimes you have to match exactly one line separator, or at least keep track of how many you're matching. In that case you need a regex that matches exactly one of any of the three most common line separator types: \r\n
(Windows/DOS), \n
(Unix/Linus/OSX) and \r
(older Macs). Either of these will do:
\r\n|[\r\n]
\r\n|\n|\r
Update: As of Java 8 we have another option, \R. It matches any line separator, including not just \r\n
, but several others as defined by the Unicode standard. It's equivalent to this:
\r\n|[\n\x0B\x0C\r\u0085\u2028\u2029]
Here's how you might use it:
(?im)^.*www.*\R.*Pig.*$
The i
option makes it case-insensitive, and the m
puts it in multiline mode, allowing ^
and $
to match at line boundaries.
回答2:
For future reference, one can also use the Pattern.DOTALL flag for "." to match even \r or \n.
Example:
Say the we are parsing a single string of http header lines like this (each line ended with \r\n)
HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: SAMEORIGIN
Location: http://localhost:8080/blah.htm
Content-Length: 0
This pattern:
final static Pattern PATTERN_LOCATION = Pattern.compile(".*?Location\\: (.*?)\\r.*?", Pattern.DOTALL);
Can parse the location value using "matcher.group(1)".
The "." in the above pattern will match \r and \n, so the above pattern can actually parse the 'Location' from the http header lines, where there might be other headers before or after the target line (not that this is a recommended way to parse http headers).
Also, you can use "?s" inside the pattern to achieve the same effect.
If you are doing this, you might be better off using Matcher.find().
回答3:
Works for me:
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class Foo {
public static void main(String args[]) {
Pattern p = Pattern.compile(".*www.*\\s.*Pig.*");
String s = "www.foo.com/Archives/monkeys.htm\n"
+ "Description of Monkey's website.\n"
+ "\n"
+ "www.foo.com/Archives/pigs.txt\n"
+ "Description of Pig's website.\n"
+ "\n"
+ "www.foo.com/Archives/kitty.txt\n"
+ "Description of Kitty's website.\n"
+ "\n"
+ "www.foo.com/Archives/apple.htm\n"
+ "Description of Apple's website.\n";
Matcher m = p.matcher(s);
if (m.find()) {
System.out.println(m.group());
} else {
System.out.println("ERR: no match");
}
}
}
Perhaps the problem was with the way you were using the Pattern and Matcher objects?
回答4:
try this
([^\r]+\r[^\r])+
回答5:
This version matches newlines that may be either Windows (\r\n) or Unix (\n)
Pattern p = Pattern.compile("(www.*)((\r\n)|(\n))(.*Pig.*)");
String s = "www.foo.com/Archives/monkeys.htm\n"
+ "Description of Monkey's website.\n"
+ "\r\n"
+ "www.foo.com/Archives/pigs.txt\r\n"
+ "Description of Pig's website.\n"
+ "\n"
+ "www.foo.com/Archives/kitty.txt\n"
+ "Description of Kitty's website.\n"
+ "\n"
+ "www.foo.com/Archives/apple.htm\n"
+ "Description of Apple's website.\n";
Matcher m = p.matcher(s);
if (m.find()) {
System.out.println("found: "+m.group());
System.out.println("website: "+m.group(1));
System.out.println("description: "+m.group(5));
}
System.out.println("done");
来源:https://stackoverflow.com/questions/3445326/regex-in-java-how-to-deal-with-newline