Dictionary Optional? Confusion in swift - xcode

I know there are a lot of posts on this, but I can't seem to figure out what's going on. The dictionary prints fine. It has a list of words with the number of letters for that word as the value. I want to check if another string is in the list. I read a bunch on optionals, but apparently I'm missing something. I think it has to do with that of course.
let path = NSBundle.mainBundle().pathForResource("wordlist", ofType: "txt")
var content = String.stringWithContentsOfFile(path, encoding: NSUTF8StringEncoding, error: nil)?.componentsSeparatedByString("\n")
var myDict = [String : Int]()
let compareWord : String? = "TEST"
if let content = content {
for word in 100 ..< 105
{
myDict[content[word]] = countElements(content[word])
}
}
println("\(myDict)")
var num : Int? = 0
println("Num: \(myDict[compareWord!])")
if let num : Int = myDict[compareWord!] {
println("\(compareWord) is a word with \(num) letters")
}
else
{
println("Wasn't a word")
}
**** Updated with a bit more detail of the code.
Here is what I get when I print a section of the dictionary.
[ABBOTSHIPS
: 11, ABBREVIATED
: 12, ABBOTS
: 7, ABBOTSHIP
: 10, ABBREVIATE
: 11]
If I set the test word to one of them I always get nil when checking for it. It seems to work fine when I manually type things in under the playground.

Ensure that componentsSeparatedByString("\n") doesn't leave any other character, such as \r, at the beginning or end of each extracted strings.

Related

Google Sheets API adding single qoute to text

Hi I am running a Google APi script to enter data into a sheet but for some text (number,dates, booleans) it's adding a ' before e.g 05/01/2021 = '05/01/2021
I am using batch update:
def turn_into_range(data, SheetId, row,cols):
rows = [{'values': [{'userEnteredValue': {'stringValue': f}} for f in e]} for e in data]
rng = {'sheetId': SheetId, 'startRowIndex': 0, 'startColumnIndex': 0}
fields = 'userEnteredValue'
body = {'requests': [{'updateCells': {'rows': rows, 'range': rng, 'fields': fields}},{
"updateSheetProperties": {
"properties": {
"gridProperties": {
"rowCount": row + 1,
"columnCount": cols
},
"sheetId": SheetId
},
"fields": "gridProperties"
},
}
]}
clean_dict = simplejson.loads(simplejson.dumps(body, ignore_nan=True))
return clean_dict
def post_sheet(service_sheets, spreadsheet_id, body):
request = service_sheets.spreadsheets().batchUpdate(spreadsheetId=spreadsheet_id, body=body)
response = request.execute()
return response
any ideas?
For this issue, it is because your data is treated as string in stringValue.
You need to use other types of values for different data types,
stringValue:
"A String", # Represents a string value.
Leading single quotes are not included. For example, if the user typed '123 into the UI, this would be represented as a stringValue of "123".
boolValue:
True or False, # Represents a boolean value.
numberValue:
3.14, # Represents a double value.
Note: Dates, Times and DateTimes are represented as doubles in "serial number" format.
formulaValue:
"A String", # Represents a formula.
errorValue:
An error in a cell. Represents an error.
This field is read-only.
Try adding this in your code.
from dateutil.parser import parse
def checkData(data):
if (isinstance(data, bool)):
return 'boolValue'
try:
if (isinstance(data, (int, float)) or parse(data)):
return 'numberValue'
except ValueError:
return 'stringValue'
Behaviour:
Now, use it in your code:
rows = [{'values': [{'userEnteredValue': {checkData(f): f}} for f in e]} for e in data]
For more details, documentation can be found here

LINQ: select rows where any word of string start with a certain character

I want extract from a table all rows where in a column (string) there is at least one word that starts with a specified character.
Example:
Row 1: 'this is the first row'
Row 2: 'this is th second row'
Row 3: 'this is the third row'
If the specified character is T -> I would extract all 3 rows
If the specified character is S -> I would extract only the second column
...
Please help me
Assuming you mean "space delimited sequence of characters, or begin to space or space to end" by "word", then you can split on the delimiter and test them for matches:
var src = new[] {
"this is the first row",
"this is th second row",
"this is the third row"
};
var findChar = 'S';
var lowerFindChar = findChar.ToLower();
var matches = src.Where(s => s.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Any(w => w.ToLower()[0] == lowerFindChar));
The LINQ Enumerable.Any method tests a sequence to see if any element matches, so you can split each string into a sequence of words and see if any word begins with the desired letter, compensating for case.
Try this:
rows.Where(r => Regex.IsMatch(r, " [Tt]"))
You can replace the Tt with Ss (both assuming you want either upper case or lower case).
The problem of course is, what is a "word"?
Is the character sequence 'word' in the sentence above a word according to your definition? It doesn't start with a space, not even a white-space.
A definition of a word could be:
Define wordCharacter: something like A-Z, a-z.
Define word:
- the non-empty sequence of wordCharacters at the beginning of a string followed by a non-wordcharacter
- or the non-empty sequence of wordCharacters at the end of a string preceded by a non-wordcharacter
- any non-empty sequence of wordCharacters in the string preceded and followed by a non-wordcharacter
Define start of word: the first character of a word.
String: "Some strange characters: 'A', 9, äll, B9 C$ X?
- Words: Some, strange characters, A
- Not Words: 9, äll, B9, C$ X?
So you first have to specify precisely what you mean by word, then you can define functions.
I'll write it as an extension method of IEnumerable<string>. Usage will look similar to LINQ. See Extension Methods Demystified
bool IsWordCharacter(char c) {... TODO: implement your definition of word character}
static IEnumerable<string> SplitIntoWords(this string text)
{
// TODO: exception if text null
if (text.Length == 0) return
int startIndex = 0;
while (startIndex != text.Length)
{ // not at end of string. Find the beginning of the next word:
while (startIndex < text.Length && !IsWordCharacter(text[startIndex]))
{
++startIndex;
}
// now startIndex points to the first character of the next word
// or to the end of the text
if (startIndex != text.Length)
{ // found the beginning of a word.
// the first character after the word is either the first non-word character,
// or the end of the string
int indexAfterWord = startWordIndex + 1;
while (indexAfterWord < text.Length && IsWordCharacter(text[indexAfterWord]))
{
++indexAfterWord;
}
// all characters from startIndex to indexAfterWord-1 are word characters
// so all characters between startIndexWord and indexAfterWord-1 are a word
int wordLength = indexAfterWord - startIndexWord;
yield return text.SubString(startIndexWord, wordLength);
}
}
}
Now that you've got a procedure to split any string into your definition of words, your query will be simple:
IEnumerabl<string> texts = ...
char specifiedChar = 'T';
// keep only those texts that have at least one word that starts with specifiedChar:
var textsWithWordThatStartsWithSpecifiedChar = texts
// split the text into words
// keep only the words that start with specifiedChar
// if there is such a word: keep the text
.Where(text => text.SplitIntoWords()
.Where(word => word.Length > 0 && word[0] == specifiedChar)
.Any());
var yourChar = "s";
var texts = new List<string> {
"this is the first row",
"this is th second row",
"this is the third row"
};
var result = texts.Where(p => p.StartsWith(yourChar) || p.Contains(" " + yourChar));
EDITED:
Alternative way (I'm not sure it works in linq query)
var result = texts.Where(p => (" " + p).Contains(" " + yourChar));
you can use .ToLower() if you want Case-insensitive check.

removeRange() function gives empty string in Swift 2

The removeRange: is giving me an empty string in Swift 2 and I don't understand why.
The example in the apple documentation is:
var welcome = "hello!"
let range = welcome.endIndex.advancedBy(-6)..<welcome.endIndex
welcome.removeRange(range)
//I get "" as result rather than "hello" where the exclamation mark is removed
What could be the problem?
You start at the endIndex and then you go back by 6. You are now at the beginning of the word. Then you make a range to the end index and you remove the content of this range: of course there's nothing left. :)
For example, it could be this instead:
var welcome = "hello!"
let range = welcome.endIndex.advancedBy(-1)..<welcome.endIndex
welcome.removeRange(range)
Or this:
var welcome = "hello!"
let range = welcome.startIndex.advancedBy(5)..<welcome.endIndex
welcome.removeRange(range)
There's many possible combinations.
the string in apple documentation is
at the time of remove range
var welcome = "hello there!"
The value of welcome.endIndex is 6 so advancedBy(-6) means it goes to 0. Then the range = 0..<6 that means the the range cover the whole string.
If you want "hello" then change only advancedBy(-1).
var welcome = "hello!"
let range = welcome.endIndex.advancedBy(-1)..<welcome.endIndex
welcome.removeRange(range)

Manipulating strings with Swift

I am trying to divide a String in Swift. I have the following string
Program - /path/to/file.doc
I want to get three informations out of this string
Program
/path/to/file.doc
file.doc
I began with the following solution
var str = "Program - /path/to/file.doc"
let indi = str.rangeOfString("-")?.startIndex
let subString = str.substringWithRange(Range<String.Index>(start: str.startIndex, end: indi!))
let subString2 = str.substringWithRange(Range<String.Index>(start: indi!, end: str.endIndex))
This gives me the results
"Program "and
"- /path/to/file.doc"
But how can I get file.doc after the last /?
How Can i increase/decrease and range index to avoid blank spaces?
Yes, sidyll's suggestion is correct, it's a very common practice to get components of Unix path by converting it to NSURL. You may want to write something like this:
var str = "Program - /path/to/file.doc"
if let indi = str.rangeOfString(" - ")?.startIndex {
let subString = str.substringWithRange(Range<String.Index>(start: str.startIndex, end: indi))
let subString2 = str.substringWithRange(Range<String.Index>(start: indi, end: str.endIndex))
let fileName = NSURL(string: subString2).lastPathComponent()
}
I strongly suggest you don't do force unwrap like this. Consider situation if this code will work with string without a particular pattern, for example empty string. Correct, runtime error.

Swift Xcode6 beta6 regex

I want to get the characters using regex
I want to get "CDE"
var results : NSMutableArray;
var baseString = "ABCDEFG"
var regexp = NSRegularExpression(pattern: "AB.*?FG", options: nil, error: nil)
var match : NSArray = regexp.matchesInString(baseString, options: nil, range: NSMakeRange(0,countElements(baseString)));
for matches in match {
results.addObject(sampleString.substringWithRange(matches.rangeAtIndex(2)));
}
println(results);//print"CDE"
but I get error.
ERROR→
results.addObject(sampleString.substringWithRange(matches.rangeAtIndex(2)));
NSRange' is not convertible to 'Range<String.Index>'
my english isn't good.sorry..
please help me...
The regular expression is incorrect, the match will be the entire string. Instead use: (?<=AB).*?(?=FG).
Documantation: ICU User Guide Regular Expressions
Notes:
(?<=AB) means preceded by AB
(?=FG) means followed by FG
These do not capture the matched portion.
Example code:
var baseString = "ABCDEFG"
var pattern = "(?<=AB).*?(?=FG)"
if let range = baseString.rangeOfString(pattern, options: .RegularExpressionSearch) {
let found = baseString.substringWithRange(range)
println("found: \(found)")
}
Output:
found: CDE

Resources