Wrong number of characters in line returned by CTLineGetStringRange and CTLineGetGlyphCount - objective-c

I have an app where I use CoreText to draw text highlight. It works well except that when I try to get the number of characters in a line by using CTLineGetStringRange it usually gives me a number larger then it actually is. For instance in a line containing 156 characters the length of the range was 164. CTLineGetGlyphCountreturned the same number.
Does anybody have an idea why this happens? The NSAttributedStringI use to create the framesetter is using the exact same font as my UITextView.
Here is my code:
// Build the attributed string from our text data and string attribute data
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:self.text attributes:self.attributes];
// Create the Core Text framesetter using the attributed string
_framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attributedString);
// Create the Core Text frame using our current view rect bounds
UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.bounds];
_frame = CTFramesetterCreateFrame(_framesetter, CFRangeMake(0, 0), path.CGPath, NULL);
NSArray *lines = (__bridge NSArray *) CTFrameGetLines(_frame);
for (int i = 0; i < lines.count; i++) {
CTLineRef line = (__bridge CTLineRef) [lines objectAtIndex:i];
CFRange lineRange = CTLineGetStringRange(line);
NSLog(#"lineRange: %ld, %ld", lineRange.location, lineRange.length);
CFIndex glyphCount = CTLineGetGlyphCount(line);
NSLog(#"glyphCount: %ld", glyphCount);
}
My class is a subclass of UIView which is added as subview to an instance of a subclass of UITextView.
EDIT:
Here is an example string I am testin with:
textView.text = #"Marvel's The Avengers is a 2012 American superhero film produced by Marvel Studios and distributed by Walt Disney Pictures, based on the Marvel Comics superhero team of the same name.";
In this case the first line contains
"Marvel's The Avengers is a 2012 American superhero film produced by Marvel Studios and distributed by Walt Disney Pictures, based on the " which is 137 characters long. But it gives me a range for the line with length 144.
However, when I tried with the following text the results were different:
textView.text = #"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.";
Now the first line contains
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim " with length 142. But here it gives me the correct range with length 142.
I then tried with several more texts:
Text:
"The Asgardian Loki encounters the Other, the leader of an alien race known as the Chitauri. In exchange for retrieving the Tesseract, a powerful energy source of unknown potential, the Other promises Loki a Chitauri army with which he can subjugate the Earth."
Result: "The Asgardian Loki encounters the Other, the leader of an alien race known as the Chitauri. In exchange for retrieving the Tesseract, a powerful " with length 145.
Line range length: 145
Text:
"Stark and Rogers realize that simply defeating them will not be enough for Loki; he needs to overpower them publicly to validate himself as ruler of Earth."
Result: "Stark and Rogers realize that simply defeating them will not be enough for Loki; he needs to overpower them publicly to validate himself as ruler " with length 146.
Line range length: 149
So as you can see sometimes it is correct and sometimes it is not. I can't find the explanation.

I solved the problem based on the hint given in this answer.
It seems that because UITextViewinherits from UIScrollView it has an 8 pixel inset at every edge. This meant that my internal UIViewhad an 16 pixel wider room for text then my UITextView and sometimes that difference meant that it could fit one more word before going to a new line, which gave the wrong number of characters in the line.
So subtracting 16 pixels from the width of the view solved the issue for me.
However, this was only part of my solution. The other part was to remove kerning and ligatures from my attributed string in core text:
CFAttributedStringSetAttribute(string, textRange, kCTKernAttributeName, (__bridge CFTypeRef)([NSNumber numberWithFloat:0.0]));
CFAttributedStringSetAttribute(string, textRange, kCTLigatureAttributeName, (__bridge CFTypeRef)([NSNumber numberWithInt:0]));
Now the lines fit perfectly.

Related

Modify gps-sdr-sim to point antennas away from Earth's nadir

I'm currently trying to simulate the performance of a a custom PNT satellite constellation I have designed in software. I have parsed the satellite ephemeris data into RINEX Navigation file format and fed it successfully into gps-sdr-sim. However, I now need to modify gps-sdr-sim to somehow "point" the "GPS" antennas away/outwards from Earth since the purpose of the PNT constellation is to service Cislunar users.
I've only found the following line of code which suggests the receiver (based on Earth) uses the elevation angle in the sky/above horizon to calculate the appropriate gain based on the antenna pattern.
ibs = (int)((90.0-rho.azel[1]*R2D)/5.0); // covert elevation to boresight
ant_gain = ant_pat[ibs];
There's also this checkSatVisibility function that just simply checks if it's above the horizon (elvMask = 0).
int checkSatVisibility(ephem_t eph, gpstime_t g, double *xyz, double elvMask, double *azel)
{
double llh[3],neu[3];
double pos[3],vel[3],clk[3],los[3];
double tmat[3][3];
if (eph.vflg != 1)
return (-1); // Invalid
xyz2llh(xyz,llh);
ltcmat(llh, tmat);
satpos(eph, g, pos, vel, clk);
subVect(los, pos, xyz);
ecef2neu(los, tmat, neu);
neu2azel(azel, neu);
if (azel[1]*R2D > elvMask)
return (1); // Visible
// else
return (0); // Invisible
}
I'm thinking I can modify this to be TRUE if and only if the satellite is not hidden in the two below cases (Top and Side):

How do i subscribe to onscroll event in Blazor?

I am trying to react to the onscroll event in Blazor to animate an image when the user scrolls down the web page (something like the brand logo on this website: https://lebenswelten-stgabriel.at/). I have tried the native onscroll events and also tried to use the js interop but it doesn't do anything. Is it something that is currently unavailable in Blazor or could I just be listening to the scrolling event on the wrong component?
After a couple of trials and errors, I decided to create a custom .net service that I register over on the js side. The service looks a something like this:
using System;
using Microsoft.JSInterop;
namespace myBlazorApp.Services
{
public class ScrollInfoService: IScrollInfoService
{
public event EventHandler<int> OnScroll;
public ScrollInfoService(IJSRuntime jsRuntime)
{
RegisterServiceViaJsRuntime(jsRuntime);
}
private void RegisterServiceViaJsRuntime(IJSRuntime jsRuntime)
{
jsRuntime.InvokeVoidAsync("RegisterScrollInfoService", DotNetObjectReference.Create(this));
}
public int YValue { get; private set; }
[JSInvokable("OnScroll")]
public void JsOnScroll(int yValue)
{
YValue = yValue;
Console.WriteLine("ScrollInfoService.OnScroll " + yValue);
OnScroll?.Invoke(this, yValue);
}
}
public interface IScrollInfoService
{
event EventHandler<int> OnScroll;
int YValue { get; }
}
}
The service receives the onscroll event from the DOM and raises an event on the .net side. Here is what the script looks like on the js side:
window.onscroll = function() {
if (window.scrollInfoService != null)
window.scrollInfoService.invokeMethodAsync('OnScroll', window.pageYOffset);
}
window.RegisterScrollInfoService = (scrollInfoService) => {
window.scrollInfoService = scrollInfoService;
}
I then inject my service in any Blazor component that needs it like this:
#using myBlazorApp.Services
#inject IScrollInfoService scrollInfoService
#implements IDisposable
<div>
...
</div>
#code {
protected override void OnInitialized()
{
scrollInfoService.OnScroll += OnScroll;
}
private void OnScroll(object sender, int yValue)
{
DoSomething(yValue);
}
public void Dispose()
{
scrollInfoService.OnScroll -= OnScroll;
}
}
This is how to get scrollTop for myDiv div via eval (weird but working) - see it in action on Blazor REPL.
#inject IJSRuntime JSRuntime;
<h1>DIV scrollTop: #ScrollTop</h1>
<div id="myDiv" style="overflow:scroll; height:400px;" #onscroll="#OnScroll" >
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
</div>
#code {
public int ScrollTop { get; set; }
private async Task OnScroll(EventArgs e)
{
ScrollTop = await JSRuntime.InvokeAsync<int>(
"eval", "document.getElementById('myDiv').scrollTop");
}
}
UPDATE: the similar way to do that but without using eval - thanks to Kristian Mariyanov. See it in action on Blazor REPL here - here you need to add JS custom function getScrollToTop to DOM window object:
<script>
window.getScrollToTop = (selector) => {
return document.querySelector(selector).scrollTop
}
</script>
and invoke it this way:
ScrollTop = await JS.InvokeAsync<int>("getScrollToTop", "#myDiv");
You can easily handle the Blazor OnScroll event by simply creating a Razor page that works as follows:
#page "/ScrollTest"
<h3>Scrolling</h3>
<div class="scroll" #onscroll="OnScroll">
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
fdsgdf qsdfsqdf sqfgdsfgdfg rtg ret rez
</div>
<div class="m-2 p-2">Scroll events: #counter</div>
<style>
div.scroll {
margin: 4px, 4px;
padding: 4px;
width: 500px;
height: 110px;
overflow-x: hidden;
overflow-y: auto;
text-align: justify;
}
</style>
#code {
private int counter;
private void OnScroll()
{
counter++;
}
}

Regular Expression for validate price in decimal

I really unable to find any workaround for regular expression to input price in decimal.
This what I want:-
12345
12345.1
12345.12
12345.123
.123
0.123
I also want to restrict digits.
I really created one but not validating as assumed
^([0-9]{1,5}|([0-9]{1,5}\.([0-9]{1,3})))$
Also want to know how is above expression different from the one
^([0-9]{1,5}|([0-9].([0-9]{1,3})))$ thats working fine.
Anyone with good explanation.
"I am using NSRegularExpression - Objective C" if this helps to answer more precisely
- (IBAction)btnTapped {
NSRegularExpression * regex = [NSRegularExpression regularExpressionWithPattern:
#"^\\d{1,5}([.]\\d{1,3})?|[.]\\d{1,3}$" options:NSRegularExpressionCaseInsensitive error:&error];
if ([regex numberOfMatchesInString:txtInput.text options:0 range:NSMakeRange(0, [txtInput.text length])])
NSLog(#"Matched : %#",txtInput.text);
else
NSLog(#"Not Matched : %#",txtInput.text);
}
"I am doing it in a buttonTap method".
This simple one should suit your needs:
\d*[.]?\d+
"Digits (\d+) that can be preceded by a dot ([.]?), which can itself be preceded by digits (\d*)."
Since you're talking about prices, neither scientific notation nor negative numbers are necessary.
Just as a point of interest, here's the one I usually used, scientific notation and negative numbers included:
[-+]?\d*[.]?\d+(?:[eE][-+]?\d+)?
For the new requirements (cf. comments), you can't specify how many digits you want on the first regex I gave, since it's not the way it has been built.
This one should suit your needs better:
\d{1,5}([.]\d{1,3})?|[.]\d{1,3}
"Max 5 digits (\d{1,5}) possibly followed ((...)?) by a dot itself followed by max 3 digits ([.]\d{1,3}), or (|) simply a dot followed by max 3 digits ([.]\d{1,3})".
Let's do this per-partes:
Sign in the beginning: [+-]?
Fraction number: \.\d+
Possible combinations (after sign):
Number: \d+
Fraction without zero \.\d+
And number with fraction: \d+\.\d+
So to join it all together <sign>(number|fraction without zero|number with fraction):
^[+-]?(\d+|\.\d+|\d+\.\d+)$
If you're not restricting the lengths to 5 digits before the decimal and 3 digits after then you could use this:
^[+-]?(?:[0-9]*\.[0-9]|[0-9]+)$
If you are restricting it to 5 before and 3 after max then you'd need something like this:
^[+-]?(?:[0-9]{0,5}\.[0-9]{1,3}|[0-9]{1,5})$
As far as the difference between your regexes goes, the first one limits the length of the number of digits before the decimal marker to 1-5 with and without decimals present. The second one only allows a single digit in front of the decimal pointer and 1-5 digits if there is no decimal.
How about this: ^([+-])?(\d+)?([.,])?(\d+)?$
string input = "bla";
if (!string.IsNullOrWhiteSpace(input))
{
string pattern = #"^(\s+)?([-])?(\s+)?(\d+)?([,.])?(\d+)(\s+)?$";
input = input.Replace("\'", ""); // Remove thousand's separator
System.Text.RegularExpressions.Regex.IsMatch(input, pattern);
// if server culture = de then reverse the below replace
input = input.Replace(',', '.');
}
Edit:
Oh oh - just realized that's where we run into a little bit of a problem if an en-us user uses ',' as thousand's separator....
So here a better one:
string input = "+123,456";
if (!string.IsNullOrWhiteSpace(input))
{
string pattern = #"^(\s+)?([+-])?(\s+)?(\d+)?([.,])?(\d+)(\s+)?$";
input = input.Replace(',', '.'); // Ensure no en-us thousand's separator
input = input.Replace("\'", ""); // Remove thousand's separator
input = System.Text.RegularExpressions.Regex.Replace(input, #"\s", ""); // Remove whitespaces
bool foo = System.Text.RegularExpressions.Regex.IsMatch(input, pattern);
if (foo)
{
bool de = false;
if (de) // if server-culture = de
input = input.Replace('.', ',');
double d = 0;
bool bar = double.TryParse(input, out d);
System.Diagnostics.Debug.Assert(foo == bar);
Console.WriteLine(foo);
Console.WriteLine(input);
}
else
throw new ArgumentException("input");
}
else
throw new NullReferenceException("input");
Edit2:
Instead of going through the hassle of getting the server culture, just use the tryparse overload with the culture and don't resubstitute the decimal separator.
double.TryParse(input
, System.Globalization.NumberStyles.Any
, new System.Globalization.CultureInfo("en-US")
, out d
);

UIWebView, input type, how to add percent value

I have a UIWebView, it has a table, and I want it 80% of the UIWebView size, but in de NSString I use as html:
"<table width = \"80%\", align = \"center\">"
I have a warning:
Invalid conversion specifier '"'**
because it is waiting for a d or # or whatever.
I try to see the html, using NSLog, and the % is missing
<table width = "80", align = "center">
how can I tell the NSString the % value? Thank you in advance
use '%%' instead of '%'
NSLog(#"<table width = \"80%%\", align = \"center\">");
I assume you are defining NSString using stringWithFormat so you should use '%%'. escape sequence for % is %%.

How do I lex this input?

I currently have a working, simple language implemented in Java using ANTLR. What I want to do is embed it in plain text, in a similar fashion to PHP.
For example:
Lorem ipsum dolor sit amet
<% print('consectetur adipiscing elit'); %>
Phasellus volutpat dignissim sapien.
I anticipate that the resulting token stream would look something like:
CDATA OPEN PRINT OPAREN APOS STRING APOS CPAREN SEMI CLOSE CDATA
How can I achieve this, or is there a better way?
There is no restriction on what might be outside the <% block. I assumed something like <% print('%>'); %>, as per Michael Mrozek's answer, would be possible, but outside of a situation like that, <% would always indicate the start of a code block.
Sample Implementation
I developed a solution based on ideas given in Michael Mrozek's answer, simulating Flex's start conditions using ANTLR's gated semantic predicates:
lexer grammar Lexer;
#members {
boolean codeMode = false;
}
OPEN : {!codeMode}?=> '<%' { codeMode = true; } ;
CLOSE : {codeMode}?=> '%>' { codeMode = false;} ;
LPAREN : {codeMode}?=> '(';
//etc.
CHAR : {!codeMode}?=> ~('<%');
parser grammar Parser;
options {
tokenVocab = Lexer;
output = AST;
}
tokens {
VERBATIM;
}
program :
(code | verbatim)+
;
code :
OPEN statement+ CLOSE -> statement+
;
verbatim :
CHAR -> ^(VERBATIM CHAR)
;
but outside of a situation like that, <% would always indicate the start of a code block.
In that case, first scan the file for your embedded code, and once you have those, parse your embedded code with a dedicated parser (without the noise before the <% and after the %> tags).
ANTLR has the option to let the lexer parse just a (small) part of an input file and ignore the rest. Note that you cannot create a "combined grammar" (parser and lexer in one) in that case. Here's how you can create such a "partial lexer":
// file EmbeddedCodeLexer.g
lexer grammar EmbeddedCodeLexer;
options{filter=true;} // <- enables the partial lexing!
EmbeddedCode
: '<%' // match an open tag
( String // ( match a string literal
| ~('%' | '\'') // OR match any char except `%` and `'`
| {input.LT(2) != '>'}?=> '%' // OR only match a `%` if `>` is not ahead of it
)* // ) <- zero or more times
'%>' // match a close tag
;
fragment
String
: '\'' ('\\' . | ~('\'' | '\\'))* '\''
;
If you now create a lexer from it:
java -cp antlr-3.2.jar org.antlr.Tool EmbeddedCodeLexer.g
and create a little test harness:
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
String source = "Lorem ipsum dolor sit amet \n"+
"<% \n"+
"a = 2 > 1 && 10 % 3; \n"+
"print('consectetur %> adipiscing elit'); \n"+
"%> \n"+
"Phasellus volutpat dignissim sapien. \n"+
"foo <% more code! %> bar \n";
ANTLRStringStream in = new ANTLRStringStream(source);
EmbeddedCodeLexer lexer = new EmbeddedCodeLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
for(Object o : tokens.getTokens()) {
System.out.println("=======================================\n"+
"EmbeddedCode = "+((Token)o).getText());
}
}
}
compile it all:
javac -cp antlr-3.2.jar *.java
and finally run the Main class by doing:
// *nix/MacOS
java -cp .:antlr-3.2.jar Main
// Windows
java -cp .;antlr-3.2.jar Main
it will produce the following output:
=======================================
EmbeddedCode = <%
a = 2 > 1 && 10 % 3;
print('consectetur %> adipiscing elit');
%>
=======================================
EmbeddedCode = <% more code! %>
The actual concept looks fine, although it's unlikely you'd have a PRINT token; the lexer would probably emit something like IDENTIFIER, and the parser would be responsible for figuring out that it's a function call (e.g. by looking for IDENTIFIER OPAREN ... CPAREN) and doing the appropriate thing.
As for how to do it, I don't know anything about ANTLR, but it probably has something like flex's start conditions. If so, you can have the INITIAL start condition do nothing but look for <%, which would switch to the CODE state where all the actual tokens are defined; then '%>' would switch back. In flex it would be:
%s CODE
%%
<INITIAL>{
"<%" {BEGIN(CODE);}
. {}
}
/* All these are implicitly in CODE because it was declared %s,
but you could wrap it in <CODE>{} too
*/
"%>" {BEGIN(INITIAL);}
"(" {return OPAREN;}
"'" {return APOS;}
...
You need to be careful about things like matching %> in a context where it's not a closing marker, like within a string; it's up to you if you want to allow <% print('%>'); %>, but most likely you do