-2

I'm trying to check if a String contains a time, 12 or 24 hour format, using this regex: .*([01]?[0-9]|2[0-3]):[0-5][0-9].* and used String.matches(), but it didn't seem to work. Am I doing something wrong?

Also, I know String.matches() doesn't work the same way String.contains() but I read that adding a .* at the beginning and end of the regex makes it act that way from here.

I would really appreciate it if someone could help me with this!

EDIT: An example in which I'm trying to check if a time exists in a String would be like, "The current time in London is 6:00 PM, what is the time in Toronto?", and it would return true because 6:00 PM is inside the String.

Community
  • 1
  • 1
silverAndroid
  • 960
  • 3
  • 11
  • 29
  • 3
    `SimpleDateFormat`... – Reimeus Sep 02 '15 at 19:23
  • @Reimeus I don't quite understand how I would use `SimpleDateFormat`. – silverAndroid Sep 02 '15 at 19:31
  • @stribizhev Expression rejects hours > 23, and minutes > 59, but not hours > 11 for AM/PM matching. – Andreas Sep 02 '15 at 19:41
  • 1
    Please don't use expressions like `.*something.*` with `matches()`, when you really mean find `something` using `find()`. – Andreas Sep 02 '15 at 19:43
  • @stribizhev I used `String.matches()` and `Pattern.compile(regex).matcher(String).find()` using the example `String` but for some reason they both return false, even though in the demo, it shows that it should return true. – silverAndroid Sep 02 '15 at 19:55
  • Have a look at [this demo](http://ideone.com/ji9PQr). This should work now: `str.matches("(?i).*\\b(?:(?(?:0?[0-9]|1[0-2]):[0-5][0-9](?::[0-5][0-9])?[ ]*[ap]m)|(?(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?))\\b.*")`. – Wiktor Stribiżew Sep 02 '15 at 19:57
  • OK, it works now, it's just my IDE added some extra backslashes to avoid escape sequence issues. Thanks! – silverAndroid Sep 02 '15 at 20:00

4 Answers4

2

I used Pattern and Matcher for this answer....

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class IsTimeInString {

    public static void main(String args[]){

         String string = args[0];
         System.out.println(String.format("Is there a time in here:(%1$s)", string));
         Pattern p = Pattern.compile(".*([01]?[0-9]|2[0-3]):[0-5][0-9].*");
         Matcher m = p.matcher(string);
         if(m.matches()){
             System.out.println("Yes");
         }else{
             System.out.println("No.");
         }
    }


}

Sample outputs...

$ java IsTimeInString "hi there"
Is there a time in here:(hi there)
No.

$ java IsTimeInString "hi there 2:15"
Is there a time in here:(hi there 2:15)
Yes

$ java IsTimeInString "hi there 14:15"
Is there a time in here:(hi there 14:15)
Yes
welterw8
  • 106
  • 1
  • 7
  • For Java developers, this or @stribizhev's answer works, but for Android developers, this only works because stribizhev's syntax is too complex for Android to use – silverAndroid Sep 02 '15 at 20:15
  • @silver2049 *stribizhev*'s answer is easy to retrofit to older Java, aka Android. Check my answer (works for Android too) for extended validation and usage. Both are more complex, true, it's a question of how *strict* you want the matching to be. – Andreas Sep 02 '15 at 20:27
  • @Andreas the problem is that the grouping syntax used in stribizhev's answer isn't supported as shown [here](http://imgur.com/RlGv4rM) – silverAndroid Sep 02 '15 at 20:33
1

Here is the regex that you can use:

String pattern = "(?i).*\\b(?:(?<twelve>(?:0?[0-9]|1[0-2]):[0-5][0-9](?::[0-5][0-9])?[ ]*[ap]\\.?m\\.?)|(?<twfour>(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?))\\b.*";
String str = "The current time in London is 6:00 PM, what is the time in Toronto?";
System.out.println(str.matches(pattern);

Breakdown:

(?i)       # turning on case-insensitive matching
 .*        # match anything in the beginning
  \\b      # match a word boundary
  (?:      # Below is a 12 hour format with AM/PM
    (?<twelve>(?:0?[0-9]|1[0-2]):[0-5][0-9](?::[0-5][0-9])?[ ]*[ap]\\.?m\\.?)
    |      # Below is 24 hour format
    (?<twfour>(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?)
  )
 \\b
.*

See IDEONE demo

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • Ready, IDEONE demo now is working and the answer seems complete. Note that this will also find a match if you have 13:45 PM, but I do not think it is a false positive. Else, add the look-ahead back as in my previous regex version: `(?(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?(?![ ]*[ap]m))`. – Wiktor Stribiżew Sep 02 '15 at 20:09
  • Change `` and `` to `:` for pre-Java 7 support (older Android). – Andreas Sep 02 '15 at 20:22
0

Try this

    String myString = "The current time in London is 6:00 PM";
    StringTokenizer st = new StringTokenizer(myString, "\\s+");
    SimpleDateFormat sdf = new SimpleDateFormat("h:mm a");
    SimpleDateFormat sdf1 = new SimpleDateFormat("HH:mm:ss");
    Date timeShort, timeLong;
    while(st.hasMoreTokens())
    {
        String possibleTime = st.nextToken();
        if(possibleTime.matches(".*\\d.*"))
        {
            System.out.println(possibleTime.trim());
            try {
                timeShort = sdf.parse(possibleTime);
                System.out.println("TIME: " + timeShort);
            } catch (ParseException e) {
                // Not AM/PM Time
            }
            try {
                timeLong = sdf1.parse(possibleTime);
                System.out.println("TIME: " + timeLong);
            } catch (ParseException e) {
                // Not normal Time
            }
        }
    }

result is

6:00 PM

TIME: Thu Jan 01 18:00:00 CET 1970

and later as rebuttal evidence try to parse it with JavaTime

Michele Lacorte
  • 5,323
  • 7
  • 32
  • 54
0

Update: Made space before AM/PM optional, since you sometimes see 9:45am. Also added word boundary check.

Assuming you might want to do the check more than once, it's better to precompile the regular expression.

String timeExpr = "\\b" +                      //   word boundary
                  "(?:[01]?[0-9]|2[0-3])" +    //   match 0-9, 00-09, 10-19, 20-23
                  ":[0-5][0-9]" +              //   match ':' then 00-59
                  "(?! ?[ap]m)" +              //   not followed by optional space, and 'am' or 'pm'
                  "\\b" +                      //   word boundary
                "|" +                          // OR
                  "\\b" +                      //   word boundary
                  "(?:0?[0-9]|1[0-1])" +       //   match 0-9, 00-09, 10-11
                  ":[0-5][0-9]" +              //   match ':' and 00-59
                  " ?[ap]m" +                  //   match optional space, and 'am' or 'pm'
                  "\\b";                       //   word boundary
Pattern p = Pattern.compile(timeExpr, Pattern.CASE_INSENSITIVE);

Note the "not followed by ' am' or ' pm'", otherwise it would match 17:00 PM.

You can test it like this:

String str = "The current time in London is 6:00 PM, what is the time in Toronto?";
if (p.matcher(str).find()) {
    System.out.println("Has time");
} else {
    System.out.println("Has no time");
}

Or a more complex example that actually extracts the times:

String str2 = "When it is 6:00 PM in London, is it 14:00 in Toronto?";
Matcher m = p.matcher(str2);
if (! m.find())
    System.out.println("Has no time");
else
    do {
        System.out.println("Found time: " + m.group());
    } while (m.find());

Output running both:

Has time

Found time: 6:00 PM
Found time: 14:00
Andreas
  • 154,647
  • 11
  • 152
  • 247