Hmm a może coś w tej konwencji:
<core=java>
package forum.note.model;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class BadWordLibary {
private final static Set<String> words = new HashSet<String>();
private final static Set<BadWordChain> expressions = new HashSet<BadWordChain>();
static {
// b.brzydkie :P
words.add("kurna");
words.add("cholera");
words.add("kurde");
}
static {
expressions.add(new BadWordChain("kurka", "wodna"));
expressions.add(new BadWordChain("kurna", "mać"));
expressions.add(new BadWordChain("spadaj", "na", "drzewo"));
}
public boolean isBadWord(final String word) {
if (word != null) {
return words.contains(word.toLowerCase());
}
return false;
}
public boolean isWordInChain(final Object word) {
if (word != null) {
for (final BadWordChain chain : expressions) {
if (chain.containsWord(word.toString())) {
return true;
}
}
}
return false;
}
@SuppressWarnings("unchecked")
public boolean possibleBadWordChain(final Collection words) {
if (words != null) {
for (final BadWordChain chain : expressions) {
if (chain.containsChain(words)) {
return true;
}
}
}
return false;
}
@SuppressWarnings("unchecked")
public boolean isBadWordChain(final Collection words) {
if (words != null) {
for (final BadWordChain chain : expressions) {
if (chain.matchesChain(words)) {
return true;
}
}
}
return false;
}
/**
* Ciąg brzydkich wyrażeń.
*/
private static class BadWordChain {
private final List<String> chain;
/**
* Kontruktor.
*
* @param words ciąg słów
*/
private BadWordChain(final String...words) {
this.chain = Arrays.asList(words);
}
boolean containsWord(final String word) {
if (word != null) {
return this.chain.contains(word.toLowerCase());
}
return false;
}
boolean containsChain(final Collection<Object> words) {
if (words == null || words.size() > this.chain.size()) {
return false;
}
int i = 0;
for (final Object o : words) {
if (!this.chain.get(i).equalsIgnoreCase(o.toString())) {
return false;
}
i ++;
}
return true;
}
boolean matchesChain(final Collection<Object> words) {
if (words == null || words.size() != this.chain.size()) {
return false;
}
int i = 0;
for (final Object o : words) {
if (!this.chain.get(i).equalsIgnoreCase(o.toString())) {
return false;
}
i ++;
}
return true;
}
}
}
```java
package forum.note.text;
import forum.note.model.BadWordLibary;
class CensorableTextChunk {
private final static char CENSOR_CHARACTER = '*';
private StringBuilder buffer = new StringBuilder();
private final TextType type;
private boolean isCensored = false;
public enum TextType {
WORD,
WHITESPACES
};
/**
* Konstruktor.
*
* @param t
*/
CensorableTextChunk(final TextType t) {
this.type = t;
}
public void append(final char c) {
this.buffer.append(c);
}
public boolean isBadWord(final BadWordLibary libary) {
if (this.isWord()) {
return libary.isBadWord(buffer.toString());
}
return false;
}
public void setCensored(final boolean censored) {
this.isCensored = censored;
}
public boolean isCensored() {
return this.isCensored;
}
public boolean isWord() {
return TextType.WORD.equals(this.type);
}
private String getCensoredText() {
final String censoredText;
if (this.getLength() <= 3) {
censoredText = this.getCharSequence(CENSOR_CHARACTER, this.getLength());
} else {
final int length = this.getLength();
censoredText = this.buffer.charAt(0) +
this.getCharSequence(CENSOR_CHARACTER, length - 2) +
this.buffer.charAt(length - 1);
}
return censoredText;
}
int getLength() {
return buffer.length();
}
private String getCharSequence(final char c, final int size) {
final StringBuilder sb = new StringBuilder(size);
for (int i = 0; i < size; i++) {
sb.append(c);
}
return sb.toString();
}
@Override
public String toString() {
if (this.isCensored()) {
return this.getCensoredText();
}
return buffer.toString();
}
}
package forum.note.text;
import java.util.LinkedList;
import java.util.List;
import forum.note.model.BadWordLibary;
import forum.note.text.CensorableTextChunk.TextType;
public class CensorableText {
private final List<CensorableTextChunk> textSequence = new LinkedList<CensorableTextChunk>();
private final BadWordLibary libary = new BadWordLibary();
private final char[] text;
private final char[] censoredText;
/**
* Kontruktor.
*
* @param chars tekst
*/
public CensorableText(final char[] chars) {
this.text = chars;
this.censoredText = this.createCensoredText();
}
/**
* Kontruktor.
*
* @param s tekst
*/
public CensorableText(final String s) {
this(s.toCharArray());
}
private char[] createCensoredText() {
if (this.text == null) {
return null;
}
final StringBuilder sb = new StringBuilder(this.text.length);
this.parseText();
this.censoreChains(this.textSequence);
this.censoreWords(this.textSequence);
this.append(sb, this.textSequence);
final char[] result = new char[this.text.length];
sb.getChars(0, sb.length(), result, 0);
return sb.toString().toCharArray();
}
private void parseText() {
this.textSequence.clear();
CensorableTextChunk word = new CensorableTextChunk(TextType.WORD);
CensorableTextChunk whitespace = new CensorableTextChunk(TextType.WHITESPACES);
for (final char c : this.text) {
if (Character.isLetter(c)) {
if (whitespace.getLength() > 0) {
this.textSequence.add(whitespace);
whitespace = new CensorableTextChunk(TextType.WHITESPACES);
}
word.append(c);
} else {
if (word.getLength() > 0) {
this.textSequence.add(word);
word = new CensorableTextChunk(TextType.WORD);
}
whitespace.append(c);
}
}
if (word.getLength() > 0) {
this.textSequence.add(word);
}
if (whitespace.getLength() > 0) {
this.textSequence.add(whitespace);
}
}
protected void censoreChains(final List<CensorableTextChunk> text) {
final List<CensorableTextChunk> chain = new LinkedList<CensorableTextChunk>();
for (final CensorableTextChunk chunk : text) {
this.checkChain(chain);
if (chunk.isWord() && this.libary.isWordInChain(chunk)) {
chain.add(chunk);
}
}
chain.clear();
}
private void checkChain(final List<CensorableTextChunk> chain) {
if (chain.size() > 0) {
if (libary.isBadWordChain(chain)) {
for (final CensorableTextChunk chunk : chain) {
chunk.setCensored(true);
}
chain.clear();
} else if (!libary.possibleBadWordChain(chain)){
chain.clear();
}
}
}
protected void censoreWords(final List<CensorableTextChunk> text) {
for (final CensorableTextChunk chunk : text) {
if (chunk.isBadWord(this.libary)) {
chunk.setCensored(true);
}
}
}
protected void append(final StringBuilder buffer,
final List<CensorableTextChunk> text) {
for (final CensorableTextChunk chunk : text) {
buffer.append(chunk);
}
}
public char[] getCensoredChars() {
return this.censoredText;
}
public String getCensoredText() {
return new String(this.censoredText);
}
@Override
public String toString() {
return new String(this.text);
}
}
package forum.note.text;
import javax.swing.text.BadLocationException;
import javax.swing.text.GapContent;
import javax.swing.text.Segment;
class CensoredGapContent extends GapContent {
private static final long serialVersionUID = -2643330287968357188L;
@Override
public void getChars(final int where, final int len, final Segment segment)
throws BadLocationException {
final int end = where + len;
this.checkLocation(where, end);
final int gapStart = this.getGapStart();
final int gapEnd = this.getGapEnd();
final char[] censoredText = this.getCensoredText();
if ((where + len) <= gapStart) {
// below gap
segment.array = censoredText;
segment.offset = where;
} else if (where >= gapStart) {
// above gap
segment.array = censoredText;
segment.offset = gapEnd + where - gapStart;
} else {
// spans the gap
int before = gapStart - where;
if (segment.isPartialReturn()) {
segment.array = censoredText;
segment.offset = where;
segment.count = before;
return;
}
// partial return not allowed, must copy
segment.array = new char[len];
segment.offset = 0;
System.arraycopy(censoredText, where, segment.array, 0, before);
System.arraycopy(censoredText, gapEnd, segment.array, before, len - before);
}
segment.count = len;
}
private void checkLocation(final int where, final int end) throws BadLocationException {
if (where < 0 || end < 0) {
throw new BadLocationException("Invalid location", -1);
}
if (end > length() || where > length()) {
throw new BadLocationException("Invalid location", length() + 1);
}
}
private char[] getCensoredText() {
final CensorableText text = new CensorableText((char[]) this.getArray());
return text.getCensoredChars();
}
}
package forum.note.text;
import javax.swing.text.PlainDocument;
public class CensoredDocument extends PlainDocument {
private static final long serialVersionUID = 2615069452316401682L;
/**
* Konstruktor.
*/
public CensoredDocument() {
super(new CensoredGapContent());
}
}
Wówczas podpina się to tak:
JTextArea area = new JTextArea();
area.setDocument(new CensoredDocument());