AVSpeechSynthesizer - How to detect dot for milliseconds pause (iPHONE - iPAD / iOS7 xcode) - xcode

I want to read a very long text:
NSString *text =#"Long test with dot. I want speaching pause when read dot. How can I do?";
AVSpeechSynthesizer *synthesizer = [AVSpeechSynthesizer new];
[synthesizer setDelegate:self];
AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:text];
utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:[self.defaults objectForKey:LANGUAGE]];
utterance.rate = 0.28;
[synthesizer speakUtterance:utterance];
I want synthesizer detect dot and pause for 100 millisecond.
Is it possible? How can I do ??

I mean a dot (.)
but maybe I found a solution also fot char ',' :
NSString *text = #"Line one. LineTwo aftre a pause. Line three, pause here again.";
text = [text stringByReplacingOccurrencesOfString:#"," withString:#"."];
NSArray *a = [text componentsSeparatedByString:#"."];
for(NSString *line in a)
{
AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:line];
utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:[self.defaults objectForKey:LINGUA]];
utterance.rate = 0.28;
utterance.**postUtteranceDelay** = 0.3;
[self.synthesizer speakUtterance:utterance];
}

Related

finding word after the match using NSString

I have varius log files to read. Each logs contain a report of a devices (printers).
What I can find is always the word 'firmware:' followed by the firmware revision like:
PTRE firmware: XER8673B2
The log does not seem to be very ordered, whereby the position of this text is not always on the same point or on the same line, but is always in the "PTRE firmawre: XXXXXXX" format.
How can I find XER8673B2 ? Any help is appreciated.
SOLVED (thanks to #roman-sausarnes), this is the code:
NSString *stringToSearch = [[NSString alloc] initWithContentsOfFile:#"path/to/log" encoding:NSUTF8StringEncoding error:nil];
NSString *preMatchString = #"PTRE firmware: ";
NSString *terminatingCharacter = #" ";
NSString *result = [[NSString alloc] init];
NSScanner *scanner = [NSScanner scannerWithString:stringToSearch];
[scanner scanUpToString:preMatchString intoString:NULL];
[scanner scanString:preMatchString intoString:NULL];
[scanner scanUpToString:terminatingCharacter intoString:&result];
NSLog(#"It's : %#", result);
The output is
It's : XER8673B2
Look at NSScanner. The code would look something like this:
NSString *stringToSearch = theStringThatYouWantToSearch;
NSString *preMatchString = #"firmware: ";
NSString *terminatingCharacter = " ";
NSString *result = [[NSString alloc] init];
NSScanner *scanner = [NSScanner scannerWithString:stringToSearch];
[scanner scanUpToString:preMatchString intoString:NULL];
[scanner scanString:preMatchString intoString:NULL];
[scanner scanUpToString:terminatingCharacter intoString:&result];
At the end, result should be the string that came after "firmware: " but before the next trailing space (" ").

Truncate the last line of multi-line NSTextField

I'm trying to create a text field similar to Finder's file labels. I would like the last (second) line to be truncated in the middle.
I started with a multi-line NSTextField.
However, calling [self.cell setLineBreakMode:NSLineBreakByTruncatingMiddle]; results in a the text field showing only a single truncated line (no line breaks anymore).
Here is what it looks like in Finder:
If you want to wrap text like finder labels, using two labels doesn't do you any good since you need to know what the maximum breakable amount of text is on the first line. Plus, if you're building something that will display a lot of items two labels will overburden the GUI needlessly.
Set your NSTextField.cell like this:
[captionLabel.cell setLineBreakMode: NSLineBreakByCharWrapping];
Then find the code for "NS(Attributed)String+Geometrics" (Google it, it's out there). You must #import "NS(Attributed)String+Geometrics.h"
to measure text. It monkey patches NSString and NSAttributedString
I include the following code to wrap text exactly how Finder does in its captions. Using one label below the icon it assumes that, like Finder, there will be two lines of caption.
First this is how you will call the following code in your code:
NSString *caption = self.textInput.stringValue;
CGFloat w = self.captionLabel.bounds.size.width;
NSString *wrappedCaption = [self wrappedCaptionText:self.captionLabel.font caption:caption width:w];
self.captionLabel.stringValue = wrappedCaption ? [self middleTruncatedCaption:wrappedCaption withFont:self.captionLabel.font width:w] : caption;
Now for the main code:
#define SINGLE_LINE_HEIGHT 21
/*
This is the way finder captions work -
1) see if the string needs wrapping at all
2) if so find the maximum amount that will fit on the first line of the caption
3) See if there is a (word)break character somewhere between the maximum that would fit on the first line and the begining of the string
4) If there is a break character (working backwards) on the first line- insert a line break then return a string so that the truncation function can trunc the second line
*/
-(NSString *) wrappedCaptionText:(NSFont*) aFont caption:(NSString*)caption width:(CGFloat)captionWidth
{
NSString *wrappedCaption = nil;
//get the width for the text as if it was in a single line
CGFloat widthOfText = [caption widthForHeight:SINGLE_LINE_HEIGHT font:aFont];
//1) nothing to wrap
if ( widthOfText <= captionWidth )
return nil;
//2) find the maximum amount that fits on the first line
NSRange firstLineRange = [self getMaximumLengthOfFirstLineWithFont:aFont caption:caption width:captionWidth];
//3) find the first breakable character on the first line looking backwards
NSCharacterSet *notAlphaNums = [NSCharacterSet alphanumericCharacterSet].invertedSet;
NSCharacterSet *whites = [NSCharacterSet whitespaceAndNewlineCharacterSet];
NSRange range = [caption rangeOfCharacterFromSet:notAlphaNums options:NSBackwardsSearch range:firstLineRange];
NSUInteger splitPos;
if ( (range.length == 0) || (range.location < firstLineRange.length * 2 / 3) ) {
// no break found or break is too (less than two thirds) far to the start of the text
splitPos = firstLineRange.length;
} else {
splitPos = range.location+range.length;
}
//4) put a line break at the logical end of the first line
wrappedCaption = [NSString stringWithFormat:#"%#\n%#",
[[caption substringToIndex:splitPos] stringByTrimmingCharactersInSet:whites],
[[caption substringFromIndex:splitPos] stringByTrimmingCharactersInSet:whites]];
return wrappedCaption;
}
/*
Binary search is great..but when we split the caption in half, we dont have far to go usually
Depends on the average length of text you are trying to wrap filenames are not usually that long
compared to the captions that hold them...
*/
-(NSRange) getMaximumLengthOfFirstLineWithFont:(NSFont *)aFont caption:(NSString*)caption width:(CGFloat)captionWidth
{
BOOL fits = NO;
NSString *firstLine = nil;
NSRange range;
range.length = caption.length /2;
range.location = 0;
NSUInteger lastFailedLength = caption.length;
NSUInteger lastSuccessLength = 0;
int testCount = 0;
NSUInteger initialLength = range.length;
NSUInteger actualDistance = 0;
while (!fits) {
firstLine = [caption substringWithRange:range];
fits = [firstLine widthForHeight:SINGLE_LINE_HEIGHT font:aFont] < captionWidth;
testCount++;
if ( !fits ) {
lastFailedLength = range.length;
range.length-= (lastFailedLength - lastSuccessLength) == 1? 1 : (lastFailedLength - lastSuccessLength)/2;
continue;
} else {
if ( range.length == lastFailedLength -1 ) {
actualDistance = range.length - initialLength;
#ifdef DEBUG
NSLog(#"# of tests:%d actualDistance:%lu iteration better? %#", testCount, (unsigned long)actualDistance, testCount > actualDistance ? #"YES" :#"NO");
#endif
break;
} else {
lastSuccessLength = range.length;
range.length += (lastFailedLength-range.length) / 2;
fits = NO;
continue;
}
}
}
return range;
}
-(NSString *)middleTruncatedCaption:(NSString*)aCaption withFont:(NSFont*)aFont width:(CGFloat)captionWidth
{
NSArray *components = [aCaption componentsSeparatedByString:#"\n"];
NSString *secondLine = [components objectAtIndex:1];
NSString *newCaption = aCaption;
CGFloat widthOfText = [secondLine widthForHeight:SINGLE_LINE_HEIGHT font:aFont];
if ( widthOfText > captionWidth ) {
//ignore the fact that the length might be an odd/even number "..." will always truncate at least one character
int middleChar = ((int)secondLine.length-1) / 2;
NSString *newSecondLine = nil;
NSString *leftSide = secondLine;
NSString *rightSide = secondLine;
for (int i=1; i <= middleChar; i++) {
leftSide = [secondLine substringToIndex:middleChar-i];
rightSide = [secondLine substringFromIndex:middleChar+i];
newSecondLine = [NSString stringWithFormat:#"%#…%#", leftSide, rightSide];
widthOfText = [newSecondLine widthForHeight:SINGLE_LINE_HEIGHT font:aFont];
if ( widthOfText <= captionWidth ) {
newCaption = [NSString stringWithFormat:#"%#\n%#", [components objectAtIndex:0], newSecondLine];
break;
}
}
}
return newCaption;
}
Cheers!
PS Tested in prototype works great probably has bugs...find them
I suspect there are two labels there. The top one contains the first 20 characters of a file name, and the second contains any overflow, truncated.
The length of the first label is probably restricted based on the user's font settings.

IBAction float, have a equal different numbers depending on input

New to objective-c and I just can't find the answer to this question anywhere. I'm running a IBAction for a calculation but I need the input from a label to actually equal something else in the equation.
For example:
-(IBAction)calculate; {
float a = 1.05 if ([label1.text] == 1in);
a = 2.07 if ([label1.text] == 2in);
a = 3.07 if ([label1.text] == 3in);
float b = a*([textField1.text floatValue]);
label2.text = [[NSString alloc] initWithFormat:#"%2.f", b];
}
I know I'm not even close to getting it right but I hope you get the idea as to what I'm looking for.
Thank you!
- (void)calculate {
float a;
if ([self.inputField.text isEqualToString:#"1in"]) a = 1.05f;
else if ([self.inputField.text isEqualToString:#"2in"]) a = 2.07f;
else if ([self.inputField.text isEqualToString:#"3in"]) a = 3.07f;
else a = 0.0f;
if (a) {
float b = a * ([self.inputField.text floatValue]);
self.inputField.text = [[NSString alloc] initWithFormat:#"%.2f", b];
}
else self.inputField.text = #"Invalid";
}
- (void)viewDidLoad
{
//...
self.inputField = [[UITextField alloc] initWithFrame:CGRectMake(10.0f, 20.0f, 300.0f, 30.0f)];
[self.inputField setBackgroundColor:[UIColor grayColor]];
[self.view addSubview:self.inputField];
UIButton * doneButton = [[UIButton alloc] initWithFrame:CGRectMake(10.0f, 55.0f, 300.0f, 30.0f)];
[doneButton setBackgroundColor:[UIColor blackColor]];
[doneButton setTitle:#"Done" forState:UIControlStateNormal];
[doneButton addTarget:self action:#selector(calculate) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:doneButton];
[doneButton release];
}
Note: I replaced the output format %2.f to %.2f, cause I guess you may need this format. E.g:
Input > 1in
Output< 1.05
Input > 2in
Output< 4.14
Input > 3in
Output< 9.21

Cocoa - Trim all leading whitespace from NSString

(have searched, but not been able to find a simple solution to this one either here, or in Cocoa docs)
Q. How can I trim all leading whitespace only from an NSString? (i.e. leaving any other whitespace intact.)
Unfortunately, for my purposes, NSString's stringByTrimmingCharactersInSet method works on both leading and trailing.
Mac OS X 10.4 compatibility needed, manual GC.
This creates an NSString category to do what you need. With this, you can call NSString *newString = [mystring stringByTrimmingLeadingWhitespace]; to get a copy minus leading whitespace. (Code is untested, may require some minor debugging.)
#interface NSString (trimLeadingWhitespace)
-(NSString*)stringByTrimmingLeadingWhitespace;
#end
#implementation NSString (trimLeadingWhitespace)
-(NSString*)stringByTrimmingLeadingWhitespace {
NSInteger i = 0;
while ((i < [self length])
&& [[NSCharacterSet whitespaceCharacterSet] characterIsMember:[self characterAtIndex:i]]) {
i++;
}
return [self substringFromIndex:i];
}
#end
This is another solution using Regular Expressions (requires iOS 3.2):
NSRange range = [string rangeOfString:#"^\\s*" options:NSRegularExpressionSearch];
NSString *result = [string stringByReplacingCharactersInRange:range withString:#""];
And if you want to trim the trailing whitespaces only you can use #"\\s*$" instead.
This code is taking blanks.
NSString *trimmedText = [strResult stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSLog(#"%#",trimmedText);
Here is a very efficient (uses CoreFoundation) way of doing it (Taken from kissxml):
- (NSString *)trimWhitespace {
NSMutableString *mStr = [self mutableCopy];
CFStringTrimWhitespace((CFMutableStringRef)mStr);
NSString *result = [mStr copy];
[mStr release];
return [result autorelease];
}
NSString *myText = #" foo ";
NSString *trimmedText = [myText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSLog(#"old = [%#], trimmed = [%#]", myText, trimmedText);
Here's what I would do, and it doesn't involve categories!
NSString* outputString = inputString;
NSRange range = [inputString rangeOfCharacterFromSet: [NSCharacterSet whitespaceCharacterSet]
options:0];
if (range.location == 0)
outputString = [inputString substringFromIndex: range.location + range.length];
This is much less code.
I didn't really have much time to test this, and I'm not sure if 10.4 contains the UTF8String method for NSString, but here's how I'd do it:
NSString+Trimming.h
#import <Foundation/Foundation.h>
#interface NSString (Trimming)
-(NSString *) stringByTrimmingWhitespaceFromFront;
#end
NSString+Trimming.m
#import "NSString+Trimming.h"
#implementation NSString (Trimming)
-(NSString *) stringByTrimmingWhitespaceFromFront
{
const char *cStringValue = [self UTF8String];
int i;
for (i = 0; cStringValue[i] != '\0' && isspace(cStringValue[i]); i++);
return [self substringFromIndex:i];
}
#end
It may not be the most efficient way of doing this but it should work.
str = [str stringByReplacingOccurrencesOfString:#" " withString:#""];

cocoa: NSString not removing all the characters

I have an int and for some reason it isn't working after 16 or so. Here's my code:
NSArray *sortedArray;
sortedArray = [doesntContainAnother sortedArrayUsingFunction:firstNumSort context:NULL];
int count2 = [sortedArray count];
//NSLog(#"%d", count2);
int z = 0;
while (z < count2) {
NSString *myString = [sortedArray objectAtIndex:z];
NSString *intstring = [NSString stringWithFormat:#"%d", z];
NSString *stringWithoutSpaces;
stringWithoutSpaces = [[myString stringByReplacingOccurrencesOfString:intstring
withString:#""] mutableCopy];
[hopefulfinal addObject:stringWithoutSpaces];
NSLog(#"%#", [hopefulfinal objectAtIndex:z]);
z++;
}
Edit: It's not the int, it's the stringWithoutSpaces line... I can't figure out what's causing it.
So it (the NSLog, see above the z++) looks like this:
"Here"
"whatever"
"17 whatevere"
"18 this"
etc.
I'm guessing this is related to your earlier question Sort NSArray’s by an int contained in the array, and that you're trying to strip the leading number and whitespace from an array that looks like the one you had in that question:
"0 Here is an object"
"1 What the heck, here's another!"
"2 Let's put 2 here too!"
"3 Let's put this one right here"
"4 Here's another object"
Without know the full input, I'd guess that your code is likely failing because the leading numbers and the value of z are getting out of sync. Since you don't seem to actually care what the leading number is and just want to vamoose it, I'd recommend a different approach that scans for leading digits and extracts the substring from the position where those digits end:
NSArray *array = [NSArray arrayWithObjects:#"1 One",
#"2 Two",
#"5 Five",
#"17 Seventeen",
nil];
NSMutableArray *results = [NSMutableArray array];
NSScanner *scanner;
NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
for (NSString *item in array) {
scanner = [NSScanner scannerWithString:item];
[scanner scanInteger:NULL]; // throwing away the BOOL return value...
// if string does not start with a number,
// the scanLocation will be 0, which is good.
[results addObject:[[item substringFromIndex:[scanner scanLocation]]
stringByTrimmingCharactersInSet:whitespace]];
}
NSLog(#"Resulting array is: %#", results);
// Resulting array is: (
// One,
// Two,
// Five,
// Seventeen
// )
)

Resources