use of com.ichi2.utils.JSONObject in project AnkiChinaAndroid by ankichinateam.
the class Finder method findReplace.
/**
* Find and replace fields in a note
*
* @param col The collection to search into.
* @param nids The cards to be searched for.
* @param src The original text to find.
* @param dst The text to change to.
* @param isRegex If true, the src is treated as a regex. Default = false.
* @param field Limit the search to specific field. If null, it searches all fields.
* @param fold If true the search is case-insensitive. Default = true.
* @return Number of notes with fields that were updated.
*/
public static int findReplace(Collection col, List<Long> nids, String src, String dst, boolean isRegex, String field, boolean fold) {
Map<Long, Integer> mmap = new HashMap<>();
if (field != null) {
for (JSONObject m : col.getModels().all()) {
JSONArray flds = m.getJSONArray("flds");
for (int fi = 0; fi < flds.length(); ++fi) {
JSONObject f = flds.getJSONObject(fi);
if (f.getString("name").equalsIgnoreCase(field)) {
mmap.put(m.getLong("id"), f.getInt("ord"));
}
}
}
if (mmap.isEmpty()) {
return 0;
}
}
// find and gather replacements
if (!isRegex) {
src = Pattern.quote(src);
dst = dst.replace("\\", "\\\\");
}
if (fold) {
src = "(?i)" + src;
}
Pattern regex = Pattern.compile(src);
ArrayList<Object[]> d = new ArrayList<>();
String snids = Utils.ids2str(nids);
nids = new ArrayList<>();
try (Cursor cur = col.getDb().getDatabase().query("select id, mid, flds from notes where id in " + snids, null)) {
while (cur.moveToNext()) {
String flds = cur.getString(2);
String origFlds = flds;
// does it match?
String[] sflds = Utils.splitFields(flds);
if (field != null) {
long mid = cur.getLong(1);
if (!mmap.containsKey(mid)) {
// note doesn't have that field
continue;
}
int ord = mmap.get(mid);
sflds[ord] = regex.matcher(sflds[ord]).replaceAll(dst);
} else {
for (int i = 0; i < sflds.length; ++i) {
sflds[i] = regex.matcher(sflds[i]).replaceAll(dst);
}
}
flds = Utils.joinFields(sflds);
if (!flds.equals(origFlds)) {
long nid = cur.getLong(0);
nids.add(nid);
// order based on query below
d.add(new Object[] { flds, col.getTime().intTime(), col.usn(), nid });
}
}
}
if (d.isEmpty()) {
return 0;
}
// replace
col.getDb().executeMany("update notes set flds=?,mod=?,usn=? where id=?", d);
long[] pnids = Utils.toPrimitive(nids);
col.updateFieldCache(pnids);
col.genCards(pnids);
return d.size();
}
use of com.ichi2.utils.JSONObject in project AnkiChinaAndroid by ankichinateam.
the class Finder method _findTemplate.
private String _findTemplate(String val) {
// were we given an ordinal number?
Integer num = null;
try {
num = Integer.parseInt(val) - 1;
} catch (NumberFormatException e) {
num = null;
}
if (num != null) {
return "c.ord = " + num;
}
// search for template names
List<String> lims = new ArrayList<>();
for (JSONObject m : mCol.getModels().all()) {
JSONArray tmpls = m.getJSONArray("tmpls");
for (int ti = 0; ti < tmpls.length(); ++ti) {
JSONObject t = tmpls.getJSONObject(ti);
String templateName = t.getString("name");
Normalizer.normalize(templateName, Normalizer.Form.NFC);
if (templateName.equalsIgnoreCase(val)) {
if (m.getInt("type") == Consts.MODEL_CLOZE) {
// if the user has asked for a cloze card, we want
// to give all ordinals, so we just limit to the
// model instead
lims.add("(n.mid = " + m.getLong("id") + ")");
} else {
lims.add("(n.mid = " + m.getLong("id") + " and c.ord = " + t.getInt("ord") + ")");
}
}
}
}
return TextUtils.join(" or ", lims.toArray(new String[lims.size()]));
}
use of com.ichi2.utils.JSONObject in project AnkiChinaAndroid by ankichinateam.
the class Finder method _findField.
private String _findField(String field, String val) {
/*
* We need two expressions to query the cards: One that will use JAVA REGEX syntax and another
* that should use SQLITE LIKE clause syntax.
*/
String sqlVal = val.replace("%", // For SQLITE, we escape all % signs
"\\%").replace("*", // And then convert the * into non-escaped % signs
"%");
/*
* The following three lines make sure that only _ and * are valid wildcards.
* Any other characters are enclosed inside the \Q \E markers, which force
* all meta-characters in between them to lose their special meaning
*/
String javaVal = val.replace("_", "\\E.\\Q").replace("*", "\\E.*\\Q");
/*
* For the pattern, we use the javaVal expression that uses JAVA REGEX syntax
*/
Pattern pattern = Pattern.compile("\\Q" + javaVal + "\\E", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
// find models that have that field
Map<Long, Object[]> mods = new HashMap<>();
for (JSONObject m : mCol.getModels().all()) {
JSONArray flds = m.getJSONArray("flds");
for (int fi = 0; fi < flds.length(); ++fi) {
JSONObject f = flds.getJSONObject(fi);
String fieldName = f.getString("name");
fieldName = Normalizer.normalize(fieldName, Normalizer.Form.NFC);
if (fieldName.equalsIgnoreCase(field)) {
mods.put(m.getLong("id"), new Object[] { m, f.getInt("ord") });
}
}
}
if (mods.isEmpty()) {
// nothing has that field
return null;
}
LinkedList<Long> nids = new LinkedList<>();
try (Cursor cur = mCol.getDb().getDatabase().query("select id, mid, flds from notes where mid in " + Utils.ids2str(new LinkedList<>(mods.keySet())) + " and flds like ? escape '\\'", new String[] { "%" + sqlVal + "%" })) {
while (cur.moveToNext()) {
String[] flds = Utils.splitFields(cur.getString(2));
int ord = (Integer) mods.get(cur.getLong(1))[1];
String strg = flds[ord];
if (pattern.matcher(strg).matches()) {
nids.add(cur.getLong(0));
}
}
}
if (nids.isEmpty()) {
return "0";
}
return "n.id in " + Utils.ids2str(nids);
}
use of com.ichi2.utils.JSONObject in project AnkiChinaAndroid by ankichinateam.
the class Finder method fieldNames.
public List<String> fieldNames(Collection col, boolean downcase) {
Set<String> fields = new HashSet<>();
List<String> names = new ArrayList<>();
for (JSONObject m : col.getModels().all()) {
JSONArray flds = m.getJSONArray("flds");
for (int fi = 0; fi < flds.length(); ++fi) {
JSONObject f = flds.getJSONObject(fi);
if (!fields.contains(f.getString("name").toLowerCase(Locale.US))) {
names.add(f.getString("name"));
fields.add(f.getString("name").toLowerCase(Locale.US));
}
}
}
if (downcase) {
return new ArrayList<>(fields);
}
return names;
}
use of com.ichi2.utils.JSONObject in project AnkiChinaAndroid by ankichinateam.
the class Finder method ordForMid.
/**
* Find duplicates
* ***********************************************************
*/
public static Integer ordForMid(Collection col, Map<Long, Integer> fields, long mid, String fieldName) {
if (!fields.containsKey(mid)) {
JSONObject model = col.getModels().get(mid);
JSONArray flds = model.getJSONArray("flds");
for (int c = 0; c < flds.length(); c++) {
JSONObject f = flds.getJSONObject(c);
if (f.getString("name").equalsIgnoreCase(fieldName)) {
fields.put(mid, c);
break;
}
}
}
return fields.get(mid);
}
Aggregations