tags:

views:

34

answers:

2

Ideally all of my data would look like this:

William Faulkner - 'Light In August'
William Faulkner - 'Sanctuary'
William Faulkner - 'The Sound and the Fury'

In that case, this regex would seem to work fine:

Pattern pattern = Pattern.compile("^\\s*(.*)\\s+-\\s+'(.*)'\\s*$");
Matcher matcher = pattern.matcher("William Faulkner - 'Light In August'");

if (matcher.matches()) {
    String author = matcher.group(1).trim();
    String bookTitle = matcher.group(2).trim();

    System.out.println(author + " / " + bookTitle);
}
else {
   System.out.println("No match!");
}

But occasionally my data contains examples like these, which do not seem to be matched by the pattern above:

Saki - 'Esme'
Saki - 'The Unrest Cure' (Second Edition)
Saki (File Under: Hector Hugh Munro) - 'The Interlopers' (Anniversary Multi-pack)
William Faulkner - 'The Sound and the Fury' (Collector's Re-issue)
'The Sound and the Fury'
The Sound and the Fury
The Bible (St James Version)

In all cases where no hyphen exists, these are book titles without authors. I have not found any cases of an author's name appearing without a book title.

How could I change my regex to handle this correctly?

+3  A: 

I wouldn't try to use a single regex for this. Instead, I'd use a sequence (or tree) of regexes to test for the various alternative syntaxes, in some order that gives the best results. And, I'd make it clear that there may be some input sets where the results won't be perfect ... no matter what heuristics you use.

Stephen C
+1  A: 

This regex matches all cases you described:

  ^\s*(?:(.*)\s+-\s+)?'?([^']+'?.*)\s*$

As Java string, it is: "^\\s*(?:(.*)\\s+-\\s+)?'?([^']+'?.*)\\s*$"

If you use JDK7, you can use named capturing group like this:

  ^\s*(?:(?<Author>.*)\s+-\s+)?'?(?<Title>[^']+'?.*)\s*$

where <$<Author> and <$<Title> refer to the captured group, in replacement part.

Vantomex
Awesome! Thanks!
snoopy
Vantomex