- added versioning to Wiki

git-svn-id: https://svn.berlios.de/svnroot/repos/yacy/trunk@3327 6c8d7289-2bf4-0310-a012-ef5d649a1542
pull/1/head
karlchenofhell 18 years ago
parent 10ebcb5e1e
commit f2e6f19b90

@ -19,7 +19,12 @@
last edited by #[author]# | change date #[date]# | <a href="Wiki.html?page=#[pagename]#&amp;edit=Edit">Edit</a> #(access)#(only granted to admin)::#(/access)#
</p>
</div>
<p class="Navigation"><a href="Wiki.html">Start Page</a> - <a href="Wiki.html?index=Index">Index</a> - #(access)#<a href="Wiki.html?access=all">Grant Write Access to Everybody</a>::<a href="Wiki.html?access=admin">Grant Write Access to Admin only</a>#(/access)#</p>
<p class="Navigation">
<a href="Wiki.html">Start Page</a> -
<a href="Wiki.html?index=Index">Index</a> -
<a href="Wiki.html?page=#[pagename]#&amp;diff=">Versions</a> -
#(access)#<a href="Wiki.html?access=all">Grant Write Access to Everybody</a>::<a href="Wiki.html?access=admin">Grant Write Access to Admin only</a>#(/access)#
</p>
::
<!-- 1: edit -->
<form action="Wiki.html" method="post" enctype="multipart/form-data" accept-charset="UTF-8">
@ -106,6 +111,39 @@
<p class="Navigation">
<a href="Wiki.html">Start Page</a>
</p>
::
<!-- 4: Diff -->
#(error)#<!-- no error -->
<form method="get" action="Wiki.html">
<fieldset><legend>Select versions of page '#[page]#</legend>
<input type="hidden" name="page" value="#[page]#" />
<dl>
<dt><label for="old">Compare version from</label>:</dt>
<dd>
<select id="old" name="old">#{versions}#
<option value="#[date]#"#(oldselected)#:: selected="selected"#(/oldselected)#>#[fdate]#</option>#{/versions}#
</select>
</dd>
<dt><label for="new">with version from</label>:</dt>
<dd>
<select id="new" name="new">
<optgroup label="current"><option value="#[curdate]#"#(curselected)#:: selected="selected"#(/curselected)#>#[curfdate]#</option></optgroup>#{versions}#
<option value="#[date]#"#(newselected)#:: selected="selected"#(/newselected)#>#[fdate]#</option>#{/versions}#
</select>
</dd>
<dt><input type="submit" name="diff" value="Compare" /></dt>
</dl>
</fieldset>
</form>
::<!-- IO error -->
<p class="error">IO Error reading wiki database: #[message]#</p>
::<!-- no entries available for #[name]# -->
#(/error)#
#[diff]#
<p class="Navigation">
<a href="Wiki.html">Start Page</a> -
<a href="Wiki.html?page=#[page]#">Return to #[page]#</a>
</p>
#(/mode)#
<p>Changes will be published as announcement on YaCyNews</p>

@ -53,6 +53,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import de.anomic.data.Diff;
import de.anomic.data.wikiBoard;
import de.anomic.http.httpHeader;
import de.anomic.plasma.plasmaSwitchboard;
@ -155,7 +156,7 @@ public class Wiki {
prop.put("mode_author", author);
prop.put("mode_date", dateString(new Date()));
prop.putWiki("mode_page", post.get("content", ""));
prop.put("mode_page-code", post.get("content", "").replaceAll("<","&lt;").replaceAll(">","&gt;"));
prop.put("mode_page-code", post.get("content", ""));
}
//end contrib of [MN]
@ -183,6 +184,68 @@ public class Wiki {
}
prop.put("mode_pagename", pagename);
}
else if (post.containsKey("diff")) {
prop.put("mode", 4);
prop.put("mode_page", pagename);
prop.put("mode_error_page", pagename);
try {
Iterator it = switchboard.wikiDB.keysBkp(true);
wikiBoard.entry entry;
wikiBoard.entry oentry = null;
wikiBoard.entry nentry = null;
int count = 0;
boolean oldselected = false, newselected = false;
while (it.hasNext()) {
entry = switchboard.wikiDB.readBkp((String)it.next());
prop.put("mode_error_versions_" + count + "_date", wikiBoard.dateString(entry.date()));
prop.put("mode_error_versions_" + count + "_fdate", dateString(entry.date()));
if (wikiBoard.dateString(entry.date()).equals(post.get("old", null))) {
prop.put("mode_error_versions_" + count + "_oldselected", 1);
oentry = entry;
oldselected = true;
} else if (wikiBoard.dateString(entry.date()).equals(post.get("new", null))) {
prop.put("mode_error_versions_" + count + "_newselected", 1);
nentry = entry;
newselected = true;
}
count++;
}
count--; // don't show current version
if (!oldselected) // select latest old entry
prop.put("mode_error_versions_" + (count - 1) + "_oldselected", 1);
if (!newselected) // select latest new entry (== current)
prop.put("mode_error_curselected", 1);
if (count == 0) {
prop.put("mode_error", 2); // no entries found
} else {
prop.put("mode_error_versions", count);
}
entry = switchboard.wikiDB.read(pagename);
if (entry != null) {
prop.put("mode_error_curdate", wikiBoard.dateString(entry.date()));
prop.put("mode_error_curfdate", dateString(entry.date()));
}
if (nentry == null) nentry = entry;
if (post.get("diff", "").length() > 0 && oentry != null && nentry != null) {
// TODO: split into paragraphs and compare them with the same diff-algo
Diff diff = new Diff(
new String(oentry.page(), "UTF-8"),
new String(nentry.page(), "UTF-8"), 5);
prop.putASIS("mode_diff", Diff.toHTML(new Diff[] { diff }));
} else {
prop.put("mode_diff", "");
}
} catch (IOException e) {
prop.put("mode_error", 1); //IO Error reading Wiki
prop.put("mode_error_message", e.getMessage());
}
}
else {
// show page

@ -34,7 +34,7 @@
/* --------------- global elements -------------------------- */
* {
font-family:Helvetica, Arial, sans-serif;
font-family:/*Helvetica, Arial, */sans-serif;
}
body {
@ -165,6 +165,17 @@ legend {
padding: 8px;
}
.diff {
margin: 10px 5px;
border: 1px dashed #722;
padding: .5em;
font-family: monospace;
}
.diff .unchanged { font-family: monospace; }
.diff .added { font-family: monospace; }
.diff .deleted { font-family: monospace; text-decoration: line-through; }
.imgtable {
margin: 1px;
padding: 1px;

@ -45,15 +45,20 @@ a.extern { color: #635; }
.bookmark { border-bottom: 1px #000 dashed; }
.Tags { border-left: 2px solid black; }
a.bookmarkTitle { color: #4070a0; }
a.bookmarkTitle { color: #4070a0; }
a:hover.bookmarkTitle { color: #4070a0; }
a.bookmarkTags { color: #007050; }
a.bookmarkTags { color: #007050; }
a:hover.bookmarkTags { color: #4070a0; }
a.bookmarkAction { color: #999999; }
a.bookmarkAction { color: #999999; }
.Navigation a { color: #555; }
.Navigation a:hover { color: #777; }
.diff { background-color: #171717; }
.diff .unchanged { color: #666; }
.diff .added { color: #0A0; background-color: #053005; }
.diff .deleted { color: #B00; background-color: #390505; }
/* in Status.html */
.ProgressBar { border: 1px solid #777; }
.ProgressBarFill { background-color: #944; }

@ -132,6 +132,10 @@ a.bookmarkAction {
border-left: 2px solid black;
}
.diff { background-color: #E8E8EE; }
.diff .unchanged { color: #333; }
.diff .added { color: #090; background-color: #B5F0B5; }
.diff .deleted { color: #B00; background-color: #F9B5B5; }
/* in Status.html */

@ -136,6 +136,10 @@ a.bookmarkAction {
border-left: 2px solid black;
}
.diff { background-color: #E8E8E8; }
.diff .unchanged { color: #333; }
.diff .added { color: #090; background-color: #B5F0B5; }
.diff .deleted { color: #B00; background-color: #F9B5B5; }
/* in Status.html */

@ -133,6 +133,10 @@ a.bookmarkAction {
border-left: 2px solid black;
}
.diff { background-color: #E5FFC5; }
.diff .unchanged { color: #333; }
.diff .added { color: #090; background-color: #B5F0B5; }
.diff .deleted { color: #B00; background-color: #F9B5B5; }
/* in Status.html */

@ -144,6 +144,10 @@ a.bookmarkAction {
border-left: 2px solid black;
}
.diff { background-color: #171717; }
.diff .unchanged { color: #666; }
.diff .added { color: #0A0; background-color: #053005; }
.diff .deleted { color: #B00; background-color: #390505; }
/* in Status.html */

@ -143,7 +143,7 @@ public class Diff {
if (!matrix[yy + i][xx + i]) break;
if (i <= minLength && yy + i < matrix.length && xx + i < matrix[yy].length) {
// vorzeitig abgebrochen => zuwenige chars in Diagonale => weitersuchen
break;
continue;
} else {
return new int[] { rx, ry, i };
}
@ -170,6 +170,13 @@ public class Diff {
*/
public Part[] getParts() { return (Part[])this.parts.toArray(new Part[this.parts.size()]); }
public String toString() {
StringBuffer sb = new StringBuffer(this.parts.size() * 20);
for (int j=0; j<this.parts.size(); j++)
sb.append(((Part)this.parts.get(j)).toString()).append("\n");
return sb.toString();
}
/**
* This class represents a part of the diff, meaning one operation
* (or one line of a "normal" diff)
@ -220,4 +227,25 @@ public class Diff {
(this.action == ADDED) ? "+" : "-") + " " + getString();
}
}
public static String toHTML(Diff[] diffs) {
StringBuffer sb = new StringBuffer(diffs.length * 60);
Diff.Part[] ps;
for (int i=0; i<diffs.length; i++) {
sb.append("<p class=\"diff\">\n");
ps = diffs[i].getParts();
for (int j=0; j<ps.length; j++) {
sb.append("<span\nclass=\"");
switch (ps[j].getAction()) {
case Diff.Part.UNCHANGED: sb.append("unchanged"); break;
case Diff.Part.ADDED: sb.append("added"); break;
case Diff.Part.DELETED: sb.append("deleted"); break;
}
sb.append("\">").append(wikiCode.replaceXMLEntities(ps[j].getString()).replaceAll("\n", "<br />"));
sb.append("</span>");
}
sb.append("</p>");
}
return sb.toString();
}
}

@ -1,42 +1,42 @@
// wikiBoard.java
// -------------------------------------
// (C) by Michael Peter Christen; mc@anomic.de
// first published on http://www.anomic.de
// Frankfurt, Germany, 2004
// last major change: 20.07.2004
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Using this software in any meaning (reading, learning, copying, compiling,
// running) means that you agree that the Author(s) is (are) not responsible
// for cost, loss of data or any harm that may be caused directly or indirectly
// by usage of this softare or this documentation. The usage of this software
// is on your own risk. The installation and usage (starting/running) of this
// software may allow other people or application to access your computer and
// any attached devices and is highly dependent on the configuration of the
// software which must be done by the user of the software; the author(s) is
// (are) also not responsible for proper configuration and usage of the
// software, even if provoked by documentation provided together with
// the software.
//
// Any changes to this file according to the GPL as documented in the file
// gpl.txt aside this file in the shipment you received can be done to the
// lines that follows this copyright notice here, but changes must not be
// done inside the copyright notive above. A re-distribution must contain
// the intact and unchanged copyright notice.
// Contributions and changes to the program code must be marked as such.
//wikiBoard.java
//-------------------------------------
//(C) by Michael Peter Christen; mc@anomic.de
//first published on http://www.anomic.de
//Frankfurt, Germany, 2004
//last major change: 20.07.2004
//This program is free software; you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation; either version 2 of the License, or
//(at your option) any later version.
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//Using this software in any meaning (reading, learning, copying, compiling,
//running) means that you agree that the Author(s) is (are) not responsible
//for cost, loss of data or any harm that may be caused directly or indirectly
//by usage of this softare or this documentation. The usage of this software
//is on your own risk. The installation and usage (starting/running) of this
//software may allow other people or application to access your computer and
//any attached devices and is highly dependent on the configuration of the
//software which must be done by the user of the software; the author(s) is
//(are) also not responsible for proper configuration and usage of the
//software, even if provoked by documentation provided together with
//the software.
//Any changes to this file according to the GPL as documented in the file
//gpl.txt aside this file in the shipment you received can be done to the
//lines that follows this copyright notice here, but changes must not be
//done inside the copyright notive above. A re-distribution must contain
//the intact and unchanged copyright notice.
//Contributions and changes to the program code must be marked as such.
package de.anomic.data;
@ -57,7 +57,7 @@ import de.anomic.kelondro.kelondroMapObjects;
import de.anomic.kelondro.kelondroRecords;
public class wikiBoard {
public static final int keyLength = 64;
private static final String dateFormat = "yyyyMMddHHmmss";
private static final int recordSize = 512;
@ -68,9 +68,9 @@ public class wikiBoard {
private kelondroMapObjects datbase = null;
private kelondroMapObjects bkpbase = null;
private static HashMap authors = new HashMap();
public wikiBoard(File actpath, File bkppath, int bufferkb, long preloadTime) {
new File(actpath.getParent()).mkdirs();
new File(actpath.getParent()).mkdirs();
if (datbase == null) {
datbase = new kelondroMapObjects(kelondroDyn.open(actpath, bufferkb / 2 * 0x400, preloadTime, keyLength, recordSize, '_', true, false), 500);
}
@ -83,44 +83,44 @@ public class wikiBoard {
public int sizeOfTwo() {
return datbase.size() + bkpbase.size();
}
public int size() {
return datbase.size();
}
public int cacheNodeChunkSize() {
int db = datbase.cacheNodeChunkSize();
int bk = bkpbase.cacheNodeChunkSize();
return (db + bk) / 2;
}
public int cacheObjectChunkSize() {
int db = datbase.cacheObjectChunkSize();
int bk = bkpbase.cacheObjectChunkSize();
return (db + bk) / 2;
}
public int[] cacheNodeStatus() {
int[] a = datbase.cacheNodeStatus();
int[] b = bkpbase.cacheNodeStatus();
return kelondroRecords.cacheCombinedStatus(new int[][]{a, b}, 2);
}
public long[] cacheObjectStatus() {
return datbase.cacheObjectStatus();
}
public void close() {
try {datbase.close();} catch (IOException e) {}
try {bkpbase.close();} catch (IOException e) {}
}
private static String dateString() {
return dateString(new GregorianCalendar(GMTTimeZone).getTime());
return dateString(new GregorianCalendar(GMTTimeZone).getTime());
}
private static String dateString(Date date) {
return SimpleFormatter.format(date);
public static String dateString(Date date) {
return SimpleFormatter.format(date);
}
private static String normalize(String key) {
@ -136,104 +136,104 @@ public class wikiBoard {
key = key.substring(0, p) + "%20" + key.substring(p +1);
return key;
}
public static String guessAuthor(String ip) {
String author = (String) authors.get(ip);
//yacyCore.log.logDebug("DEBUG: guessing author for ip = " + ip + " is '" + author + "', authors = " + authors.toString());
return author;
}
public static void setAuthor(String ip, String author) {
authors.put(ip,author);
}
public entry newEntry(String subject, String author, String ip, String reason, byte[] page) throws IOException {
return new entry(normalize(subject), author, ip, reason, page);
return new entry(normalize(subject), author, ip, reason, page);
}
public class entry {
String key;
String key;
Map record;
public entry(String subject, String author, String ip, String reason, byte[] page) throws IOException {
record = new HashMap();
key = subject;
if (key.length() > keyLength) key = key.substring(0, keyLength);
record.put("date", dateString());
if ((author == null) || (author.length() == 0)) author = "anonymous";
record.put("author", kelondroBase64Order.enhancedCoder.encode(author.getBytes("UTF-8")));
if ((ip == null) || (ip.length() == 0)) ip = "";
record.put("ip", ip);
if ((reason == null) || (reason.length() == 0)) reason = "";
record.put("reason", kelondroBase64Order.enhancedCoder.encode(reason.getBytes("UTF-8")));
if (page == null)
record.put("page", "");
else
record.put("page", kelondroBase64Order.enhancedCoder.encode(page));
public entry(String subject, String author, String ip, String reason, byte[] page) throws IOException {
record = new HashMap();
key = subject;
if (key.length() > keyLength) key = key.substring(0, keyLength);
record.put("date", dateString());
if ((author == null) || (author.length() == 0)) author = "anonymous";
record.put("author", kelondroBase64Order.enhancedCoder.encode(author.getBytes("UTF-8")));
if ((ip == null) || (ip.length() == 0)) ip = "";
record.put("ip", ip);
if ((reason == null) || (reason.length() == 0)) reason = "";
record.put("reason", kelondroBase64Order.enhancedCoder.encode(reason.getBytes("UTF-8")));
if (page == null)
record.put("page", "");
else
record.put("page", kelondroBase64Order.enhancedCoder.encode(page));
authors.put(ip, author);
//System.out.println("DEBUG: setting author " + author + " for ip = " + ip + ", authors = " + authors.toString());
}
}
private entry(String key, Map record) {
this.key = key;
this.record = record;
}
private entry(String key, Map record) {
this.key = key;
this.record = record;
}
public String subject() {
return key;
}
public String subject() {
return key;
}
public Date date() {
try {
String c = (String) record.get("date");
if (c == null) {
System.out.println("DEBUG - ERROR: date field missing in wikiBoard");
return new Date();
public Date date() {
try {
String c = (String) record.get("date");
if (c == null) {
System.out.println("DEBUG - ERROR: date field missing in wikiBoard");
return new Date();
}
return SimpleFormatter.parse(c);
} catch (ParseException e) {
return new Date();
}
}
return SimpleFormatter.parse(c);
} catch (ParseException e) {
return new Date();
}
}
public String author() {
String a = (String) record.get("author");
if (a == null) return "anonymous";
byte[] b = kelondroBase64Order.enhancedCoder.decode(a);
if (b == null) return "anonymous";
return new String(b);
}
public String author() {
String a = (String) record.get("author");
if (a == null) return "anonymous";
byte[] b = kelondroBase64Order.enhancedCoder.decode(a);
if (b == null) return "anonymous";
return new String(b);
}
public String reason() {
String r = (String) record.get("reason");
if (r == null) return "";
byte[] b = kelondroBase64Order.enhancedCoder.decode(r);
if (b == null) return "unknown";
return new String(b);
}
public String reason() {
String r = (String) record.get("reason");
if (r == null) return "";
byte[] b = kelondroBase64Order.enhancedCoder.decode(r);
if (b == null) return "unknown";
return new String(b);
}
public byte[] page() {
String m = (String) record.get("page");
if (m == null) return new byte[0];
byte[] b = kelondroBase64Order.enhancedCoder.decode(m);
if (b == null) return "".getBytes();
return b;
}
private void setAncestorDate(Date date) {
record.put("bkp", dateString(date));
}
public byte[] page() {
String m = (String) record.get("page");
if (m == null) return new byte[0];
byte[] b = kelondroBase64Order.enhancedCoder.decode(m);
if (b == null) return "".getBytes();
return b;
}
private Date getAncestorDate() {
try {
String c = (String) record.get("date");
if (c == null) return null;
return SimpleFormatter.parse(c);
} catch (ParseException e) {
return null;
}
}
private void setAncestorDate(Date date) {
record.put("bkp", dateString(date));
}
private Date getAncestorDate() {
try {
String c = (String) record.get("date");
if (c == null) return null;
return SimpleFormatter.parse(c);
} catch (ParseException e) {
return null;
}
}
/*
public boolean hasAncestor() {
@ -245,76 +245,80 @@ public class wikiBoard {
return false;
}
}
*/
public entry getAncestor() {
Date ancDate = getAncestorDate();
if (ancDate == null) return null;
return read(key + dateString(ancDate), bkpbase);
}
*/
public entry getAncestor() {
Date ancDate = getAncestorDate();
if (ancDate == null) return null;
return read(key + dateString(ancDate), bkpbase);
}
private void setChild(String subject) {
record.put("child", kelondroBase64Order.enhancedCoder.encode(subject.getBytes()));
}
private void setChild(String subject) {
record.put("child", kelondroBase64Order.enhancedCoder.encode(subject.getBytes()));
}
private String getChildName() {
String c = (String) record.get("child");
if (c == null) return null;
byte[] subject = kelondroBase64Order.enhancedCoder.decode(c);
if (c == null) return null;
byte[] subject = kelondroBase64Order.enhancedCoder.decode(c);
if (subject == null) return null;
return new String(subject);
}
}
public boolean hasChild() {
String c = (String) record.get("child");
if (c == null) return false;
byte[] subject = kelondroBase64Order.enhancedCoder.decode(c);
if (c == null) return false;
byte[] subject = kelondroBase64Order.enhancedCoder.decode(c);
return (subject != null);
}
}
public entry getChild() {
String childName = getChildName();
if (childName == null) return null;
return read(childName, datbase);
}
String childName = getChildName();
if (childName == null) return null;
return read(childName, datbase);
}
}
public String write(entry page) {
// writes a new page and returns key
try {
// first load the old page
entry oldEntry = read(page.key);
// set the bkp date of the new page to the date of the old page
Date oldDate = oldEntry.date();
page.setAncestorDate(oldDate);
// writes a new page and returns key
try {
// first load the old page
entry oldEntry = read(page.key);
// set the bkp date of the new page to the date of the old page
Date oldDate = oldEntry.date();
page.setAncestorDate(oldDate);
oldEntry.setChild(page.subject());
// write the backup
// write the backup
//System.out.println("key = " + page.key);
//System.out.println("oldDate = " + oldDate);
//System.out.println("record = " + oldEntry.record.toString());
bkpbase.set(page.key + dateString(oldDate), oldEntry.record);
// write the new page
datbase.set(page.key, page.record);
return page.key;
} catch (IOException e) {
return null;
}
bkpbase.set(page.key + dateString(oldDate), oldEntry.record);
// write the new page
datbase.set(page.key, page.record);
return page.key;
} catch (IOException e) {
return null;
}
}
public entry read(String key) {
return read(key, datbase);
return read(key, datbase);
}
private entry read(String key, kelondroMapObjects base) {
try {
key = normalize(key);
if (key.length() > keyLength) key = key.substring(0, keyLength);
Map record = base.getMap(key);
if (record == null) return newEntry(key, "anonymous", "127.0.0.1", "New Page", "".getBytes());
return new entry(key, record);
} catch (IOException e) {
return null;
}
try {
key = normalize(key);
if (key.length() > keyLength) key = key.substring(0, keyLength);
Map record = base.getMap(key);
if (record == null) return newEntry(key, "anonymous", "127.0.0.1", "New Page", "".getBytes());
return new entry(key, record);
} catch (IOException e) {
return null;
}
}
public entry readBkp(String key) {
return read(key, bkpbase);
}
/*
@ -325,10 +329,13 @@ public class wikiBoard {
return false;
}
}
*/
*/
public Iterator keys(boolean up) throws IOException {
return datbase.keys(up, false);
return datbase.keys(up, false);
}
public Iterator keysBkp(boolean up) throws IOException {
return bkpbase.keys(up, false);
}
}

@ -171,6 +171,32 @@ public class wikiCode {
}
return text;
}
public static String deReplaceHTML(String text) {
text = deReplaceHTMLEntities(text);
text = deReplaceXMLEntities(text);
return text;
}
public static String deReplaceHTMLEntities(String text) {
return deReplace(text, htmlentities);
}
public static String deReplaceXMLEntities(String text) {
return deReplace(text, xmlentities);
}
public static String deReplace(String text, String[] entities) {
if (text == null) return null;
for (int i=entities.length-1; i>0; i-=2) {
int p = 0;
while ((p = text.indexOf(entities[i])) >= 0) {
text = text.substring(0, p) + entities[i - 1] + text.substring(p + entities[i].length());
p += entities[i - 1].length();
}
}
return text;
}
//This array contains codes (see http://mindprod.com/jgloss/unicode.html for details)
//that will be replaced. To add new codes or patterns, just put them at the end

Loading…
Cancel
Save