Is it possible to reverse a string in SPARQL, so, e.g., "abc" becomes "cba". Alternatively, is it possible to sort based on strings in reverse.
I am particularly interested in a solution that would work on Wikidata Query Service.
Is it possible to reverse a string in SPARQL, so, e.g., "abc" becomes "cba". Alternatively, is it possible to sort based on strings in reverse.
I am particularly interested in a solution that would work on Wikidata Query Service.
Well, you asked whether it's possible, not whether it's practical...
SELECT ?s (group_concat(?letter; separator='') AS ?r) {
BIND ("abcdefghijkl" AS ?s)
VALUES ?d1 { 0 1 2 3 4 5 6 7 8 9 }
VALUES ?d2 { 0 1 2 3 4 5 6 7 8 9 }
VALUES ?d3 { 0 1 2 3 4 5 6 7 8 9 }
BIND (100 * ?d3 + 10 * ?d2 + ?d1 + 1 AS ?i)
BIND (SUBSTR(?s, ?i, 1) AS ?letter)
}
GROUP BY ?s
The approach is similar to that in Finn's response, but it works for strings up to a length of 1000 characters. This would be used as a subquery within a larger query. Aggregates like group_concat
don't guarantee a particular order, so this query relies on the implementation-dependent ordering used by Blazegraph, and may jumble up the string on a different implementation.
If the use case is sorting by the last characters of a string in reverse order, then this could be tweaked so that it's guaranteed to include the last n characters of the string.
This pathological implementation apparently works (up to a certain string length, here 12) in Blazegraph/Wikidata Query Service:
SELECT ?s ?r {
BIND("abcdefghijkl" AS ?s)
BIND(CONCAT(SUBSTR(?s, 12, 1), SUBSTR(?s, 11, 1), SUBSTR(?s, 10, 1),
SUBSTR(?s, 9, 1), SUBSTR(?s, 8, 1), SUBSTR(?s, 7, 1),
SUBSTR(?s, 6, 1), SUBSTR(?s, 5, 1), SUBSTR(?s, 4, 1),
SUBSTR(?s, 3, 1), SUBSTR(?s, 2, 1), SUBSTR(?s, 1, 1)) AS ?r)
}
There is no "reverse string" function in SPARQL 1.1.
There is no ORDER BY
modifier that delivers the ordering you're looking for.
Many if not most programming and scripting languages do have "reverse string" and "sort" methods, so I'd suggest investigating whether your (unnamed) development environment has such.
Here's a query targeting Virtuoso that provides the desired solution, courtesy of a sub-query.
SELECT ?str (GROUP_CONCAT(?letter; separator="") AS ?reverse)
WHERE {
{
SELECT ?str ?charAt
WHERE {
VALUES ?str { "abcdefghijk" }
VALUES ?d1 { 0 1 2 3 4 5 6 7 8 9 10 }
BIND(STRLEN(?str) - ?d1 AS ?charAt)
FILTER(?charAt > 0)
}
}
BIND(SUBSTR(?str,?charAt,1) AS ?letter)
}