ios Replace subStrings with a pattern - ios

I have a very long string and it contains some information that I do not want. For example, it constantly has something like:
"<span class=/"phrasedesc/">....some text......</span phrasedesc>",
and I would like to remove all the substrings begin with "<span class=/"phrasedesc/">" and ends with "</span phrasedesc>", no matter what's between.
Any one can help me with this? Thank you.

Try this, it worked for me. :)
SWIFT:
let re = try! NSRegularExpression(pattern: "(.*)(《span class=\"phrasedesc\"》.*《\\/span phrasedesc》)(.*)", options: .AnchorsMatchLines)
let stringToMatch = "adfasdfasdf《span class=\"phrasedesc\"》ajshdfljkahsdkjf 《/span phrasedesc》asdfasdfasdfasdf"
let matches = re.matchesInString(stringToMatch, options: .WithTransparentBounds , range: NSRange(location: 0, length: stringToMatch.characters.count))
re.stringByReplacingMatchesInString(stringToMatch, options: .ReportCompletion, range: NSMakeRange(0, stringToMatch.characters.count), withTemplate: "$1$3")
OBJECTIVE - C:
NSString *stringToBeTrimmed = #"adfasdfasdf《span class=\"phrasedesc\"》ajshdfljkahsdkjf 《/span phrasedesc》asdfasdfasdfasdf";
NSString *pattern = #"(.*)(《span class=\"phrasedesc\"》.*《\\/span phrasedesc》)(.*)";
NSRegularExpression *expression = [[NSRegularExpression alloc] initWithPattern:pattern options:NSRegularExpressionAnchorsMatchLines error:nil];
NSString * yourResultingString = [expression stringByReplacingMatchesInString:stringToBeTrimmed options:NSMatchingReportCompletion range:NSMakeRange(0, stringToBeTrimmed.length) withTemplate:#"$1$3"];

Consider using stringByReplacingOccurrencesOfString:
Swift:
let originalString = "<span class=\"phrasedesc\">....some text......</span phrasedesc>"
let newString = originalString.stringByReplacingOccurrencesOfString("<span class=\"phrasedesc\">", withString: "")
let newString = newString.stringByReplacingOccurrencesOfString("</span phrasedesc>", withString: "")
Objective-C:
NSString *originalString = #"<span class=\"phrasedesc\">....some text......</span phrasedesc>";
newString = [originalString stringByReplacingOccurrencesOfString:#"<span class=\"phrasedesc\">" withString:#""];
newString = [newString stringByReplacingOccurrencesOfString:#"</span phrasedesc>" withString:#""];
The result will be newString == "....some text......"

Related

Can not analyse url in NSString when this string contains chinese by NSDataDetector

There have no match ====================================================
I know, it's the problem of "blank space", if I add blank at the front of "https", then it works. So NSDataDetector can not solve this problem?
NSString *originString = #"【mans】下单立减5.00元https://kdt.im/uYMI4r";
NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSArray *matches1 = [linkDetector matchesInString:originString options:0 range:NSMakeRange(0, [originString length])];
for (NSTextCheckingResult *match in matches1) {
if ([match resultType] == NSTextCheckingTypeLink) {
NSURL *url = [match URL];
}
}
This is a known issue with NSDataDetector that if there is a space before the protocol i.e. http:// or https:// then it works, otherwise it doesn't.
For e.g.
let input = "This is a test with the URL https://www.sharpkits.com to be detected."
let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
let matches = detector.matches(in: input, options: [], range: NSRange(location: 0, length: input.utf16.count))
for match in matches {
let url = (input as NSString).substring(with: match.range)
print(url)
}
Output:
https://www.sharpkits.com
and for let input = "This is a test with the URLhttps://www.sharpkits.com to be detected."
Output: URLhttps://www.sharpkits.com
So nope can't be done with NSDataDetector

Split Attributed String and Retain Formatting

How can you take an existing NSAttributedString and divide it based on a predefined separator while maintaining formatting? It does not seem that componentsSeparatedByString will operate on an NSAttributedString.
My current workaround produces the splits at the correct points, but only outputs an NSString. Thus losing formatting.
NSData *rtfFileData = [NSData dataWithContentsOfFile:path];
NSAttributedString *rtfFileAttributedString = [[NSAttributedString alloc] initWithData:rtfFileData options:#{NSDocumentTypeDocumentAttribute:NSRTFTextDocumentType} documentAttributes:nil error:nil];
NSString *rtfFileString = [rtfFileAttributedString string];
NSString *importSeparator = #"###";
// Wish I could do this
// NSArray *separatedArray = [rtfFileAttributedString componentsSeparatedByString:importSeparatorPref];
NSArray *separatedArray = [rtfFileString componentsSeparatedByString:importSeparatorPref];
NSLog( #"Separated array: %#", separatedArray );
You can make use of your split non-attributed string to split up the attributed string. One option would be:
NSData *rtfFileData = [NSData dataWithContentsOfFile:path];
NSAttributedString *rtfFileAttributedString = [[NSAttributedString alloc] initWithData:rtfFileData options:#{NSDocumentTypeDocumentAttribute:NSRTFTextDocumentType} documentAttributes:nil error:nil];
NSString *rtfFileString = [rtfFileAttributedString string];
NSString *importSeparator = #"###";
NSArray *separatedArray = [rtfFileString componentsSeparatedByString:importSeparatorPref];
NSMutableArray *separatedAttributedArray = [NSMutableArray arrayWithCapacity:separatedArray.count];
NSInteger start = 0;
for (NSString *sub in separatedArray) {
NSRange range = NSMakeRange(start, sub.length);
NSAttributedString *str = [rtfFileAttributedString attributedSubstringFromRange:range];
[separatedAttributedArray addObject:str];
start += range.length + importSeparator.length;
}
NSLog(#"Separated attributed array: ", separatedAttributedArray);
In Swift 4, I made the function.
func splitAttributedString(inputString: NSAttributedString, seperateBy: String) -> [NSAttributedString] {
let input = inputString.string
let separatedInput = input.components(separatedBy: seperateBy)
var output = [NSAttributedString]()
var start = 0
for sub in separatedInput {
let range = NSMakeRange(start, sub.utf16.count)
let attribStr = inputString.attributedSubstring(from: range)
output.append(attribStr)
start += range.length + seperateBy.count
}
return output
}
Here is an NSAttributedString extension that works in a similar fashion to some of the other examples here.
private extension NSAttributedString {
func components(separatedBy separator: String) -> [NSAttributedString] {
var result = [NSAttributedString]()
let separatedStrings = string.components(separatedBy: separator)
var range = NSRange(location: 0, length: 0)
for string in separatedStrings {
range.length = string.utf16.count
let attributedString = attributedSubstring(from: range)
result.append(attributedString)
range.location += range.length + separator.utf16.count
}
return result
}
}
In swift the answer is simple.
var string = NSAttributedString(
string: "This string is shorter than it should be for this questions answer.",
attributes: [.font: UIFont.systemFont(ofSize: 12)]
)
let range = NSRange(location: 0, length: 120)
let newString = string.attributedSubstring(from: range)
print(newString)

NSRegularExpression search string "*string*"

i have a list of string i want search string like A mean it is only appearance in middle not first or last.My code here:
When i run all 3 case is true, but only case "う上あ" is true
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSArray *array = #[#"上あう", #"う上あ", #"あう上"];
NSString *stringNeedToFind = #"*上*";
for (NSString *string in array) {
if ([[self regularExpressionFromValue: stringNeedToFind] numberOfMatchesInString:string options: 0 range: NSMakeRange(0, string.length)]) {
NSLog(#"String containt.");
}
}
}
- (NSRegularExpression *) regularExpressionFromValue: (NSString *) value
{
NSString *pattern = [NSRegularExpression escapedPatternForString: value];
pattern = [pattern stringByReplacingOccurrencesOfString: #"\\*" withString: #".*"];
pattern = [pattern stringByReplacingOccurrencesOfString: #"\\?" withString: #"."];
pattern = [pattern stringByReplacingOccurrencesOfString: #".*.*.*" withString: #"\\*"];
pattern = [pattern stringByReplacingOccurrencesOfString: #"..." withString: #"\\?\\?\\?"];
pattern = [NSString stringWithFormat: #"^%#$", pattern];
return [NSRegularExpression regularExpressionWithPattern: pattern options: 0 error: NULL];
}
As far as I know, the asterisk (*) is used as an operator to check if a character (set) is present 0 or more times. I think you should use the plus character (+), e.g. like this: ^.+上.+$, meaning there should be 1 or more characters at the start and at the end.

Detect whole word in NSStrings

How do I detect if an NSString contains a specific word, e.g. is.
If the NSString is Here is my string. His isn't a mississippi isthmus. It is...? The method should detect the word is and return YES.
However, if the NSString is His isn't a mississipi isthmus, it should return NO.
I tried using if ([text rangeOfString:#"is" options:NSCaseInsensitiveSearch].location != NSNotFound) { ... } but it detects characters not words.
Use "regular expression" search with the "word boundary pattern" \b:
NSString *text = #"Here is my string. His isn't a mississippi isthmus. It is...";
NSString *pattern = #"\\bis\\b";
NSRange range = [text rangeOfString:pattern options:NSRegularExpressionSearch|NSCaseInsensitiveSearch];
if (range.location != NSNotFound) { ... }
This works also for cases like "Is it?" or "It is!", where the word is not surrounded by spaces.
In Swift 2 this would be
let text = "Here is my string. His isn't a mississippi isthmus. It is..."
let pattern = "\\bis\\b"
if let range = text.rangeOfString(pattern, options: [.RegularExpressionSearch, .CaseInsensitiveSearch]) {
print ("found:", text.substringWithRange(range))
}
Swift 3:
let text = "Here is my string. His isn't a mississippi isthmus. It is..."
let pattern = "\\bis\\b"
if let range = text.range(of: pattern, options: [.regularExpression, .caseInsensitive]) {
print ("found:", text.substring(with: range))
}
Swift 4:
let text = "Here is my string. His isn't a mississippi isthmus. It is..."
let pattern = "\\bis\\b"
if let range = text.range(of: pattern, options: [.regularExpression, .caseInsensitive]) {
print ("found:", text[range])
}
Swift 5 (using the new raw string literals):
let text = "Here is my string. His isn't a mississippi isthmus. It is..."
let pattern = #"\bis\b"#
if let range = text.range(of: pattern, options: [.regularExpression, .caseInsensitive]) {
print ("found:", text[range])
}
Use NSRegularExpressionSearch option with \b to match word boundary characters.
Like this:
NSString *string = #"Here is my string. His isn't a mississippi isthmus. It is...";
if(NSNotFound != [string rangeOfString:#"\\bis\\b" options:NSRegularExpressionSearch].location) {//...}
What about
if ([text rangeOfString:#" is " options:NSCaseInsensitiveSearch].location != NSNotFound) { ... }
You could use regular expressions, as suggested, or you could analyze the words linguistically:
NSString *string = #"Here is my string. His isn't a mississippi isthmus. It is...";
__block BOOL containsIs = NO;
[string enumerateLinguisticTagsInRange:NSMakeRange(0, [string length]) scheme:NSLinguisticTagSchemeTokenType options:NSLinguisticTaggerOmitPunctuation | NSLinguisticTaggerOmitWhitespace | NSLinguisticTaggerOmitOther orthography:nil usingBlock:^(NSString *tag, NSRange tokenRange, NSRange sentenceRange, BOOL *stop){
NSString *substring = [string substringWithRange:tokenRange];
if (containsIs)
if ([substring isEqualToString:#"n't"])
containsIs = NO; // special case because "isn't" are actually two separate words
else
*stop = YES;
else
containsIs = [substring isEqualToString:#"is"];
}];
NSLog(#"'%#' contains 'is': %#", string, containsIs ? #"YES" : #"NO");

How do I get the substring between braces?

I have a string as this.
NSString *myString = #"{53} balloons";
How do I get the substring 53 ?
NSString *myString = #"{53} balloons";
NSRange start = [myString rangeOfString:#"{"];
NSRange end = [myString rangeOfString:#"}"];
if (start.location != NSNotFound && end.location != NSNotFound && end.location > start.location) {
NSString *betweenBraces = [myString substringWithRange:NSMakeRange(start.location+1, end.location-(start.location+1))];
}
edit: Added range check, thx to Keab42 - good point.
Here is what I did.
NSString *myString = #"{53} balloons";
NSCharacterSet *delimiters = [NSCharacterSet characterSetWithCharactersInString:#"{}"];
NSArray *splitString = [myString componentsSeparatedByCharactersInSet:delimiters];
NSString *substring = [splitString objectAtIndex:1];
the substring is 53.
For Swift 4.2:
if let r1 = string.range(of: "{")?.upperBound,
let r2 = string.range(of: "}")?.lowerBound {
print (String(string[r1..<r2]))
}
You can use a regular expression to get the number between the braces. It might seem a bit complicated but the plus side is that it will find multiple numbers and the position of the number doesn't matter.
Swift 4.2:
let searchText = "{53} balloons {12} clowns {123} sparklers"
let regex = try NSRegularExpression(pattern: "\\{(\\d+)\\}", options: [])
let matches = regex.matches(in: searchText, options: [], range: NSRange(searchText.startIndex..., in: searchText))
matches.compactMap { Range($0.range(at: 1), in: searchText) }
.forEach { print("Number: \(searchText[$0])") }
Objective-C:
NSString *searchText = #"{53} balloons {12} clowns {123} sparklers";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"\\{(\\d+)\\}"
options:0
error:nil];
NSArray *matches = [regex matchesInString:searchText
options:0
range:NSMakeRange(0, searchText.length)];
for (NSTextCheckingResult *r in matches)
{
NSRange numberRange = [r rangeAtIndex:1];
NSLog(#"Number: %#", [searchText substringWithRange:numberRange]);
}
This will print out:
Number: 53
Number: 12
Number: 123
Try this code.
NSString *myString = #"{53} balloons";
NSString *value = [myString substringWithRange:NSMakeRange(1,2)];
For Swift 2.1 :-
var start = strData?.rangeOfString("{")
var end = strData?.rangeOfString("}")
if (start!.location != NSNotFound && end!.location != NSNotFound && end!.location > start!.location) {
var betweenBraces = strData?.substringWithRange(NSMakeRange(start!.location + 1, end!.location-(start!.location + 1)))
print(betweenBraces)
}
I guess, your a looking for the NSScanner class, at least if you are addressing a general case. Have a look in Apples documentation.
Search the location for "{" and "}".
Take substring between those index.
Checked with any number of data:
NSString *str = #"{53} balloons";
NSArray* strary = [str componentsSeparatedByString: #"}"];
NSString* str1 = [strary objectAtIndex: 0];
NSString *str2 = [str1 stringByReplacingOccurrencesOfString:#"{" withString:#""];
NSLog(#"number = %#",str2);
Another method is
NSString *tmpStr = #"{53} balloons";
NSRange r1 = [tmpStr rangeOfString:#"{"];
NSRange r2 = [tmpStr rangeOfString:#"}"];
NSRange rSub = NSMakeRange(r1.location + r1.length, r2.location - r1.location - r1.length);
NSString *subString = [tmpStr substringWithRange:rSub];
If you don't know how many digits there will be, but you know it will always be enclosed with curly braces try this:
NSString *myString = #"{53} balloons";
NSRange startRange = [myString rangeOfString:#"{"];
NSRange endRange = [myString rangeOfString:#"}"];
if (startRange.location != NSNotFound && endRange.location != NSNotFound && endRange.location > startRange.location) {
NSString *value = [myString substringWithRange:NSMakeRange(startRange.location,endRange.ocation - startRange.location)];
}
There's probably a more efficient way to do it though.

Resources