Search in sources :

Example 21 with JSONObject

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();
}
Also used : Pattern(java.util.regex.Pattern) HashMap(java.util.HashMap) JSONArray(com.ichi2.utils.JSONArray) ArrayList(java.util.ArrayList) Cursor(android.database.Cursor) JSONObject(com.ichi2.utils.JSONObject)

Example 22 with JSONObject

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()]));
}
Also used : JSONObject(com.ichi2.utils.JSONObject) ArrayList(java.util.ArrayList) JSONArray(com.ichi2.utils.JSONArray)

Example 23 with JSONObject

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);
}
Also used : Pattern(java.util.regex.Pattern) HashMap(java.util.HashMap) JSONArray(com.ichi2.utils.JSONArray) Cursor(android.database.Cursor) LinkedList(java.util.LinkedList) JSONObject(com.ichi2.utils.JSONObject)

Example 24 with JSONObject

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;
}
Also used : JSONObject(com.ichi2.utils.JSONObject) ArrayList(java.util.ArrayList) JSONArray(com.ichi2.utils.JSONArray) HashSet(java.util.HashSet)

Example 25 with JSONObject

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);
}
Also used : JSONObject(com.ichi2.utils.JSONObject) JSONArray(com.ichi2.utils.JSONArray)

Aggregations

JSONObject (com.ichi2.utils.JSONObject)272 JSONArray (com.ichi2.utils.JSONArray)110 ArrayList (java.util.ArrayList)59 Test (org.junit.Test)55 Collection (com.ichi2.libanki.Collection)46 IOException (java.io.IOException)40 RobolectricTest (com.ichi2.anki.RobolectricTest)34 JSONException (com.ichi2.utils.JSONException)34 Note (com.ichi2.libanki.Note)33 Model (com.ichi2.libanki.Model)31 HashMap (java.util.HashMap)31 SuppressLint (android.annotation.SuppressLint)29 JSONObject (org.json.JSONObject)27 Response (okhttp3.Response)25 JSONException (org.json.JSONException)24 NonNull (androidx.annotation.NonNull)23 Card (com.ichi2.libanki.Card)21 File (java.io.File)21 Map (java.util.Map)20 Intent (android.content.Intent)19