I need to pull an ID out of a link using regex - swift

I have very limited experience with regex, and never used it for this type of situation, so I'm hoping someone can lead me in the right direction.
I get a link returned from a web service that will look something like this:
<a id="inventoryID-123456789" class="inventory item">See update</a>
What I need to do is create a regex that will get me back the digits in inventoryID. It will always be between 8 & 12 digits and followed by a 'class' tag.
This is using swift 4.2.
I appreciate any help.

If you are receiving a html tag and you want to get the id attribute which always has "inventoryID-<numeric id>" syntax, you could use the following pattern:
\w+-\d+
Have you tried some library for html tag parsing? It could help a lot too.

The easiest way to find an 8-12 digit numeric string is
let link = "<a id=\"inventoryID-123456789\" class=\"inventory item\">See update</a>"
if let range = link.range(of: "\\d{8,12}", options: .regularExpression) {
let inventoryID = String(link[range])
print(inventoryID)
}

Related

Different font for parameters in NSLocalizedString

I want to give a label a text that have multiple fonts in it. This can be accomplished by creating a NSMutableAttributedString. However, I am not sure how I format the following case:
String(format: NSLocalizedString("%# has replied in '%#'", comment: ""), username, conversationTitle)
I want to give the username and conversation title a separate font. I want to do this in the less buggiest way. What I mean by this:
I do not want to find out the username later on in the string by using a substring. This is causing issues when the conversationTitle is the same as the username, or the conversationTitle is in the username etc. etc..
I do not want to build up the string, as seen here: https://stackoverflow.com/a/37992022/7715250. This is just bad when creating NSLocalizedString's, I think the translators are going to have a bad time when string are created like that.
Questions like: Making text bold using attributed string in swift, Are there approaches for using attributed strings in combination with localization? and others are mostly string literals without NSLocalizedString or NSLocalizedString with parameters.
First, you should have in your .strings a much more generic and readble key, something like:
"_REPLIED_IN_" = "%# has replied in %#";
Do not confuse keys and values as you seem to do in your example.
Also, it's easier later to see when there is an hardcoded string not localized in your code.
Now, there is an issue, because in English, it might be in that order, but not necessarily in other languages.
So instead:
"_REPLIED_IN_" = "%1$# has replied in %$2#";
Now, I'll use the bold sample, because it's easier, but what you could do is use some custom tags to tell you that it needs to be bold, like HTML, MarkDown, etc.
In HTML:
"_REPLIED_IN_" = "<b>%1$#</b> has replied in <b>%$2#</b>";
You need to parse it into a NSAttributedString:
let translation = String(format: NSLocalizedString(format: "_REPLIED_IN_", comment: nil), userName, conversationTitle)
let attributedText = NSAttributedString.someMethodThatParseYourTags(translation)
It's up to you to choose the easiest tag format), according to your needs: easy to understand by translators, and easy to parse (CocoaTouch already has a HTML parser, etc.).

Extract text from a Wordnik API URL in Google Sheets

Can anyone explain how to import/extract a particular field from the following url into Google Sheets:
Wordnik URL
I'm guessing there is an IMPORTXML query that could do it, but it doesn't have the nodes that IMPORTXML usually uses to import that. Instead the code looks like this:
[{"mi":6.720745180909532,"gram1":"pretty","gram2":"much","wlmi":18.953166108085608},{"mi":6.650496643050408,"gram1":"pretty","gram2":"good","wlmi":18.469078820531266},{"mi":9.839004198061549,"gram1":"pretty","gram2":"darn","wlmi":17.298435816698845},{"mi":7.515791105774376,"gram1":"pretty","gram2":"cool","wlmi":15.515791105774376},{"mi":8.233704272151307,"gram1":"pretty","gram2":"impressive","wlmi":15.210984195651225}]
So if Cell A2 has the URL that produces this as the code, how do I get B2 to give me the text after "gram2" (in this case, "good", "darn", "cool" and "impressive").
Thanks
Tardy
I've come up with a workaround but it is kind of messy. I'd still like an answer to the question, but for reference and in case it's of use to anyone I'll post it here:
Using =IMPORTDATA(E10) (where E10 is the cell with the URL in) gave me an array (I guess based on .csv principles) that I could then manipulate using some other tools, like regexreplace, to get at the relevant bits of text.

Swift 2/3 String implement of rindexOf method

I know there is an build in method to get the index of substring from the original string by using rangeOfString. But it is used to get the first occurrence of a given substring. However what I need to do is to get the last occurrence of the given substring.
This is something like the rindex in python language
So, my question is, How can I do that in Swift 2.x/3? A code snippet example is appreciated.
You are close. Try the below, adding the optional options parameter and searching the string from the back instead.
let myString = "testingteststring"
let lastSubstringRange = myString.range(of: "test", options: String.CompareOptions.backwards)
'lastSubstringRange' will be the range of the last 'test' substring in 'myString'.
For more info, try looking at Apple Developer: https://developer.apple.com/reference/swift/string/1642786-range

Autocomplete with Firebase

How does one use Firebase to do basic auto-completion/text preview?
For example, imagine a blog backed by Firebase where the blogger can tag posts with tags. As the blogger is tagging a new post, it would be helpful if they could see all currently-existing tags that matched the first few keystrokes they've entered. So if "blog," "black," "blazing saddles," and "bulldogs" were tags, if the user types "bl" they get the first three but not "bulldogs."
My initial thought was that we could set the tag with the priority of the tag, and use startAt, such that our query would look something like:
fb.child('tags').startAt('bl').limitToFirst(5).once('value', function(snap) {
console.log(snap.val())
});
But this would also return "bulldog" as one of the results (not the end of the world, but not the best either). Using startAt('bl').endAt('bl') returns no results. Is there another way to accomplish this?
(I know that one option is that this is something we could use a search server, like ElasticSearch, for -- see https://www.firebase.com/blog/2014-01-02-queries-part-two.html -- but I'd love to keep as much in Firebase as possible.)
Edit
As Kato suggested, here's a concrete example. We have 20,000 users, with their names stored as such:
/users/$userId/name
Oftentimes, users will be looking up another user by name. As a user is looking up their buddy, we'd like a drop-down to populate a list of users whose names start with the letters that the searcher has inputted. So if I typed in "Ja" I would expect to see "Jake Heller," "jake gyllenhaal," "Jack Donaghy," etc. in the drop-down.
I know this is an old topic, but it's still relevant. Based on Neil's answer above, you more easily search doing the following:
fb.child('tags').startAt(queryString).endAt(queryString + '\uf8ff').limit(5)
See Firebase Retrieving Data.
The \uf8ff character used in the query above is a very high code point
in the Unicode range. Because it is after most regular characters in
Unicode, the query matches all values that start with queryString.
As inspired by Kato's comments -- one way to approach this problem is to set the priority to the field you want to search on for your autocomplete and use startAt(), limit(), and client-side filtering to return only the results that you want. You'll want to make sure that the priority and the search term is lower-cased, since Firebase is case-sensitive.
This is a crude example to demonstrate this using the Users example I laid out in the question:
For a search for "ja", assuming all users have their priority set to the lowercased version of the user's name:
fb.child('users').
startAt('ja'). // The user-inputted search
limitToFirst(20).
once('value', function(snap) {
for(key in snap.val()){
if(snap.val()[key].indexOf('ja') === 0) {
console.log(snap.val()[key];
}
}
});
This should only return the names that actually begin with "ja" (even if Firebase actually returns names alphabetically after "ja").
I choose to use limitToFirst(20) to keep the response size small and because, realistically, you'll never need more than 20 for the autocomplete drop-down. There are probably better ways to do the filtering, but this should at least demonstrate the concept.
Hope this helps someone! And it's quite possible the Firebase guys have a better answer.
(Note that this is very limited -- if someone searches for the last name, it won't return what they're looking for. Hence the "best" answer is probably to use a search backend with something like Kato's Flashlight.)
It strikes me that there's a much simpler and more elegant way of achieving this than client side filtering or hacking Elastic.
By converting the search key into its' Unicode value and storing that as the priority, you can search by startAt() and endAt() by incrementing the value by one.
var start = "ABA";
var pad = "AAAAAAAAAA";
start += pad.substring(0, pad.length - start.length);
var blob = new Blob([start]);
var reader = new FileReader();
reader.onload = function(e) {
var typedArray = new Uint8Array(e.target.result);
var array = Array.prototype.slice.call(typedArray);
var priority = parseInt(array.join(""));
console.log("Priority of", start, "is:", priority);
}
reader.readAsArrayBuffer(blob);
You can then limit your search priority to the key "ABB" by incrementing the last charCode by one and doing the same conversion:
var limit = String.fromCharCode(start.charCodeAt(start.length -1) +1);
limit = start.substring(0, start.length -1) +limit;
"ABA..." to "ABB..." ends up with priorities of:
Start: 65666565656565650000
End: 65666665656565650000
Simples!
Based on Jake and Matt's answer, updated version for sdk 3.1. '.limit' no longer works:
firebaseDb.ref('users')
.orderByChild('name')
.startAt(query)
.endAt(`${query}\uf8ff`)
.limitToFirst(5)
.on('child_added', (child) => {
console.log(
{
id: child.key,
name: child.val().name
}
)
})

Coldfusion Hash SHA-1 Doesnt look the same as the sample

Im working on a script to hash a "fingerprint" for communicating with the secure Pay Direct Post API.
The issue I have is im trying to create a SHA-1 String that matches the sample code provided so that i can ensure things get posted accurately.
the example Sha-1 string appears encoded like
01a1edbb159aa01b99740508d79620251c2f871d
However my string when converted appears as
7871D5C9A366339DA848FC64CB32F6A9AD8FCADD
completely different...
my code for this is as follows..
<cfset variables.finger_print = "ABC0010|txnpassword|0|Test Reference|1.00|20110616221931">
<cfset variables.finger_print = hash(variables.finger_print,'SHA-1')>
<cfoutput>
#variables.finger_print#
</cfoutput>
Im using Coldfusion 8 to do this
it generates a 40 character hash, but i can see its generating completely different strings.
Hopefully someone out there has done this before and can point me in the right direction...
thanks in advance
** EDIT
The article for creating the Hash only contains the following information.
Example: Setting the fingerprint Fields joined with a | separator:
ABC0010|txnpassword|0|Test Reference|1.00|20110616221931
SHA1 the above string: 01a1edbb159aa01b99740508d79620251c2f871d
When generating the above example string using coldfusion hash it turns it into this
7871D5C9A366339DA848FC64CB32F6A9AD8FCADD
01a1edbb159aa01b99740508d79620251c2f871d
Sorry, but I do not see how the sample string could possibly produce that result given that php, CF and java all say otherwise. I suspect an error in the documentation. The one thing that stands out is the use of "txnpassword" instead of a sample value, like with the other fields. Perhaps they used a different value to produce the string and forgot to plug it into the actual example?
Update:
Example 5.2.1.12, on page 27, makes more sense. Ignoring case, the results from ColdFusion match exactly. I noticed the description also mentions something about a summarycode value, which is absent from the example in section 3.3.6. So that tends to support the theory of documentation error with the earlier example.
Code:
<cfset input = "ABC0010|mytxnpasswd|MyReference|1000|201105231545|1">
<cfoutput>#hash(input, "sha-1")#</cfoutput>
Result:
3F97240C9607E86F87C405AF340608828D331E10