Java tutorial
/******************************************************************************* * Copyright (c) 2014,2015 Hideki Yatomi * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html ******************************************************************************/ package net.yatomiya.nicherry.services.bbs.model; import java.util.*; import java.util.regex.*; import com.squareup.okhttp.*; import net.yatomiya.e4.util.*; import net.yatomiya.nicherry.model.bbs.*; // "http://aaa.2ch.host/test/read.cgi/board_key/thread_key/message_no public class ThreadURL { HttpUrl httpUrl; String boardKey; String threadKey; MessageParam messageParam; public ThreadURL(String urlString) { httpUrl = HttpUrl.parse(urlString); List<String> seg = httpUrl.pathSegments(); if (seg.size() != 4 && seg.size() != 5) throw new IllegalArgumentException("Thread path segments size should be 5 or 6."); if (!seg.get(0).equalsIgnoreCase("test") || !seg.get(1).equalsIgnoreCase("read.cgi")) throw new IllegalArgumentException("url does not contain \\\"test/read.cgi\\\"."); boardKey = seg.get(2); threadKey = seg.get(3); if (seg.size() >= 5) { messageParam = new MessageParam(seg.get(4)); } else { messageParam = MessageParam.ALL; } } public HttpUrl getURL() { return httpUrl; } public String getHost() { return httpUrl.host(); } public String getBoardKey() { return boardKey; } public String getThreadKey() { return threadKey; } public MessageParam getMessageParam() { return messageParam; } public static class MessageParam { public static final String MESSAGE_RANGE_EXPR = "(?<headPrefix>^[\\-l]?)(?<headNumber>[\\d]+)(?<headSuffix>(-|n-)?)(?<tailNumber>[\\d]*)"; public static final Pattern MESSAGE_RANGE_PATTERN = Pattern.compile(MESSAGE_RANGE_EXPR); static final MessageParam ALL = new MessageParam(""); static enum Type { ALL, RECENT, UNTIL, FIRST_AND_FROM, FROM, ONLY, FIRST_AND_RANGE, RANGE, } Type type; int head; int tail; MessageParam(String str) { if (JUtils.isEmpty(str)) { type = Type.ALL; return; } Matcher m = MESSAGE_RANGE_PATTERN.matcher(str); if (m.find()) { String headPrefix = m.group("headPrefix"); String headNumber = m.group("headNumber"); String headSuffix = m.group("headSuffix"); String tailNumber = m.group("tailNumber"); head = -1; tail = -1; try { if (!JUtils.isEmpty(headNumber)) head = Integer.valueOf(headNumber); if (!JUtils.isEmpty(tailNumber)) tail = Integer.valueOf(tailNumber); if (head < 0 && tail < 0) { type = Type.ALL; } else if (head >= 0 && tail < 0) { if (!JUtils.isEmpty(headPrefix)) { switch (headPrefix) { case "l": type = Type.RECENT; break; case "-": type = Type.UNTIL; break; } } else if (!JUtils.isEmpty(headSuffix)) { switch (headSuffix) { case "-": type = Type.FIRST_AND_FROM; break; case "n-": type = Type.FROM; break; } } else { type = Type.ONLY; } } else if (head >= 0 && tail >= 0 && !JUtils.isEmpty(headSuffix)) { switch (headSuffix) { case "-": type = Type.FIRST_AND_RANGE; break; case "n-": type = Type.RANGE; break; } } } catch (NumberFormatException e) { type = Type.ALL; } } } public Type getType() { return type; } public int getHead() { return head; } public int getTail() { return tail; } public int getFirstMessageNo() { switch (type) { case ALL: return 1; case RECENT: return 1; case UNTIL: return 1; case FIRST_AND_FROM: return head; case FROM: return head; case ONLY: return head; case FIRST_AND_RANGE: return head; case RANGE: return head; } return 1; } /* static void test() { MessageParam p; p = new MessageParam("l50"); //"l50"???????50? p = new MessageParam("-50"); //"-50"?????1??50??? p = new MessageParam("50-"); // "50-"?????1??????50?? p = new MessageParam("50n-"); // ????????50?? p = new MessageParam("50"); //"50"???????50??? p = new MessageParam("50-60"); //????1?50-60 p = new MessageParam("50n-60"); } */ } public static ImmutableBitSet toMessageNoSet(MThread thread, MessageParam param) { int size = thread.getMessageCount(); if (size == 0) return new ImmutableBitSet(); int head = param.getHead(); int tail = param.getTail(); BitSet bs = new BitSet(); switch (param.getType()) { case ALL: bs.set(1, size); break; case RECENT: bs.set(Math.max(1, size - head), size); break; case UNTIL: bs.set(1, Math.min(size, head)); break; case FIRST_AND_FROM: bs.set(1); if (head <= size) bs.set(head, size); break; case FROM: if (head <= size) bs.set(head, size); break; case ONLY: bs.set(head); break; case FIRST_AND_RANGE: { bs.set(1); bs.set(head, tail); BitSet all = new BitSet(); all.set(1, size); bs.and(all); } break; case RANGE: { bs.set(head, tail); BitSet all = new BitSet(); all.set(1, size); bs.and(all); } break; } return new ImmutableBitSet(bs); } }