Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Line Number for Selected String in TextView

I have some text placed in an NSTextView control. Well, where my text string comes from is not important. So I won't restrict this topic only to OSX. Anyway, I can find out the current position of the selected string like...

NSRange sel = [textView1 selectedRange]; // textView1 may be NSTextView or UITextView.
NSNumber *point = [NSNumber numberWithInteger:sel.location];

How can I find out which line this selected string belongs to?

NSArray *array = [[textView1 string] componentsSeparatedByString:@"\r\n"];

Thank you for your help.

like image 838
El Tomato Avatar asked Jan 29 '26 09:01

El Tomato


2 Answers

I think the following code should do it. m is the line number to which the selected string belongs. It's based on an array. So the first line is 0, not 1. stringContains is just a function for seeing if the string (in this case, each line) contains the selected passage. There are so many lines of code for a simple number I need to return. I don't know if it's a simpler way of doing it. Note that the data type of m is set to 'unsigned' and k to 'unsigned long.' k is the number of all characters. This number and stringContains make sure that m is the line to which the selected passage belongs. If the total number of lines is large like several thousands, you may have to auto-release variables. That's for OSX.

- (void)findLineNumber {
    NSRange sel = [textView1 selectedRange];
    NSNumber *point = [NSNumber numberWithInteger:sel.location];
    NSString *selectedText = [[textView1 string] substringWithRange:[textView1 selectedRange]]; // [textView1 string] into textView1.text for iOS
    NSArray *array = [[textView1 string] componentsSeparatedByString:@"\n"]; // [textView1 string] into textView1.text for iOS

    unsigned long k = 0;
    unsigned m;
    for (unsigned i2 = 0; i2 < array.count; i2++) {
        NSString *line = [array objectAtIndex:i2];
        if (point.integerValue >= k && [self stringContains:line:selectedText]) {
            m = i2;
        }
        k += line.length;
    }

    NSLog(%i,m); // zero-based
}

- (BOOL)stringContains:(NSString *)source :(NSString *)find {
    // case-sensitive
    NSRange myRange;
    myRange = [source rangeOfString:find];
    if ([source isEqualToString:find]) {
        return true;
    } else {
        if (source.length > find.length) {
            if (myRange.location == NSNotFound) {
                return false;
            }
            else {
                return true;
            }
        } else {
            return false;
        }
    }
}
like image 114
El Tomato Avatar answered Jan 31 '26 01:01

El Tomato


You certainly shouldn’t use componentsSeparatedByString:@"\r\n”, just use \n. Native texts objects don’t use CRLF, the just use LF.

Also, note that the sel.location in your example is just the beginning of the selection—I’m not sure what you want to do if multiple characters are selected.

Anyhow, you probably want to call:

- (void)getLineStart:(NSUInteger *)startIndex end:(NSUInteger *)lineEndIndex contentsEnd:(NSUInteger *)contentsEndIndex forRange:(NSRange)aRange

Parameters
startIndex
Upon return, contains the index of the first character of the line containing the beginning of aRange. Pass NULL if you do not need this value (in which case the work to compute the value isn’t performed).
lineEndIndex
Upon return, contains the index of the first character past the terminator of the line containing the end of aRange. Pass NULL if you do not need this value (in which case the work to compute the value isn’t performed).
contentsEndIndex
Upon return, contains the index of the first character of the terminator of the line containing the end of aRange. Pass NULL if you do not need this value (in which case the work to compute the value isn’t performed).
aRange
A range within the receiver. The value must not exceed the bounds of the receiver.
Raises an NSRangeException if aRange is invalid.
like image 27
Wil Shipley Avatar answered Jan 30 '26 23:01

Wil Shipley