I have got following code:
Put_Line(Source_String (Source_String'First + Start-1..Source_String'First + Stop-2));
It works correctly, but I want to use it as a bounded string.
String1: String(1..50);
If I use
String1:= Source_String (Source_String'First + Start-1..Source_String'First + Stop-2)
But this block of code doesn't work. I can't use substring as a String. Compile doesn't output any errors, but also doesn't work
P.S. When I use Put_Line only, my program works correctly
There seems to be a misconception here : String1: String(1..50); doesn't declare a bounded string but a fixed string. Realising that, it's easy to see why the assignment usually "doesn't work" ... the slice of Source_String must be exactly 50 characters long or the assignment will give a constraint error.
One solution is to use a Bounded String, but that may not be necessary here, so I'm going to suggest a simpler approach.
Think about the program, and structure it so that the runtime values of Source_String, Start and Stop are all known before the declaration of String1. One tool you can use is the "declare block" - this allows declarations to be kept local to their point of use, which is good programming practice... Later on, when you're refactoring, these make great candidates for abstracting out into procedures.
Now you can move the assignment into the declaration, as an initialiser, and the string takes its length from the initialisation. The fact that its length is unknown until runtime doesn't matter, you can find the length from its attributes.
You can move quite a lot into the declarations, and if you don't intend to modify the contents another good practice is to make the declarations constant. So the code might look like:
Start := ...
declare
Source_String : constant String := Read_Line(File);
Stop : constant Natural := Second_Space(Source_String);
String1 : constant String := Source_String (Source_String'First + Start-1
.. Source_String'First + Stop-2);
begin
-- process String1
end; -- String1 goes out of scope here.
Related
I am totally confused about the following macro modifier in a Makefile I have come onto,
TOOLS = $(TOOL_ROOTS:%=$(OBJDIR)%$(TOOL_SUFFIX))
Here
TOOL_ROOTS=some filename prefixes
OBJDIR=$HOME/obj/
TOOL_SUFFIX=.so
Can someone tell me what this line actually means?
TOOL_ROOTS must be getting assigned some value other than the empty string at some point or that does nothing (which I'll show in a moment).
So first things first just expanding the variables takes us from:
TOOLS = $(TOOL_ROOTS:%=$(OBJDIR)%$(TOOL_SUFFIX))
to:
TOOLS = $(:%=~/obj%.so)
(which we can immediately see doesn't look right, and as I'll explain in a moment doesn't do anything)
So lets pretend it has a value instead.
TOOL_ROOTS = shovel axe hammer
And try the expansion again:
TOOLS = $(shovel axe hammer:%=~/obj%.so)
(That OBJDIR definition looks odd also. I would expect it to be ~/obj/ or something... and that's ignoring that ~ is a bad choice here and that $HOME would be much better.)
The next thing we need to know is what that syntax is all about. Well it is a Substitution Reference.
A substitution reference substitutes the value of a variable with alterations that you specify. It has the form ‘$(var:a=b)’ (or ‘${var:a=b}’) and its meaning is to take the value of the variable var, replace every a at the end of a word with b in that value, and substitute the resulting string.
When we say “at the end of a word”, we mean that a must appear either followed by whitespace or at the end of the value in order to be replaced; other occurrences of a in the value are unaltered. For example:
foo := a.o b.o c.o
bar := $(foo:.o=.c)
sets ‘bar’ to ‘a.c b.c c.c’. See Setting Variables.
A substitution reference is actually an abbreviation for use of the patsubst expansion function (see Functions for String Substitution and Analysis). We provide substitution references as well as patsubst for compatibility with other implementations of make.
Another type of substitution reference lets you use the full power of the patsubst function. It has the same form ‘$(var:a=b)’ described above, except that now a must contain a single ‘%’ character. This case is equivalent to ‘$(patsubst a,b,$(var))’. See Functions for String Substitution and Analysis, for a description of the patsubst function.
For example:
foo := a.o b.o c.o
bar := $(foo:%.o=%.c)
sets ‘bar’ to ‘a.c b.c c.c’.
So, the first % there is matching the entirety of every word in the value of the variable (here shovel axe hammer) and then replacing each value with the expansion of the second part.
So shovel becomes ~/objshovel.so, etc. and we end up with:
TOOLS = ~/objshovel.so ~/objaxe.so ~/objhammer.so
See what I meant about OBJDIR being odd before? OBJDIR=~/obj/ would have left us with this instead:
TOOLS = ~/obj/shovel.so ~/obj/axe.so ~/obj/hammer.so
which makes a lot more sense to me.
In most programming languages, 'c' is a character and "c" is a string of length 1. But Coq (according to its standard ascii and string library) uses "c" as the notation for both, which requires constant use of Open Scope to clarify which one is being referred to. How can you avoid this and designate characters in the usual way, with single quotes? It would be nice if there is a solution that only partially overrides the standard library, changing the notation but recycling the rest.
Require Import Ascii.
Require Import String.
Check "a"%char.
Check "b"%string.
or this
Program Definition c (s:string) : ascii :=
match s with "" => " "%char | String a _ => a end.
Check (c"A").
Check ("A").
I am quite confident that there is no smart way of doing this, but there is a somewhat annoying one: simply declare one notation for each character.
Notation "''c''" := "c" : char_scope.
Notation "''a''" := "a" : char_scope.
Check 'a'.
Check 'c'.
It shouldn't be too hard to write a script for automatically generating those declarations. I don't know if this has any negative side-effects on Coq's parser, though.
I'm very much a newbie to Ada and I'm trying to teach myself, with the assistance of one of John Barnes' books.
While dabbling with strings, I wrote a very basic program to read user input from the keyboard and then output it again to the console. However, when the output is produced, it appears to contain additional characters that have not been explicitly typed. Looking at it, my gut reaction is that it's unicode/Konsole-related but I definitely cannot discount whether or not it's something that I have done wrong in my code.
I have attached a screenshot of the program and its output. Any ideas would be greatly appreciated.
Thanks!
Image showing code and output
The difference is that strings are NOT null terminated; they are exactly as long as they say they are : in this case, 100 characters.
And not all the characters in your example are what you typed.
Quick fix : only output the Len characters you typed...
Put_Line ("Your String: '" & UserString(1 .. Len) & "' (Chars: " & natural'image(Len) & ")");
(I have used the standard portable natural'image(Len) rather than the compiler-specific Len'img form)
This leaves some remaining problems :
if you type more than 100 characters, the result will be safe but unsatisfactory.
you need to specify the slice boundaries (1..Len) everywhere you need the string.
Better fix : create a string of exactly the length you typed. Easiest way is calling the function form of Get_Line, and initialising an unconstrained String from the function's return value. The unconstrained String has no defined length when it is declared, it gets its length from the initialisation. For this to work, we can start a new block...
Put_Line("Enter a string: ");
declare
UserString : constant String := Get_Line;
-- the string is now the correct length, however much you typed.
begin
Put_Line ("Your String: '" & UserString & "' (Chars: " &
natural'image(UserString'Length) & ")");
-- other processing on UserString here
end;
-- UserString is now out of scope, automatically freed
Notice that there is no more need for the Len variable. The string's length is an attribute of the string, not a separate quantity that may be incorrectly managed; one less thing to go wrong.
And the declare block is a safe and powerful technique for allocating runtime sized storage without needing heap allocation routines, pointers, deallocation etc. Several less things to go wrong.
It is usually a good idea (thanks Simon!) to make UserString a Constant. Not essential (otherwise you can edit it in place, but not change its length) but assuming you don't intend to edit it - one less thing to go wrong.
There are other techniques involving Bounded_String or Unbounded_String but they aren't really necessary here.
I have the following code:
var wqry:TAdoQuery;
...
FillChar(wSpaces,cSpacesAfter,' ');
try
wqry := TADOQuery.Create(nil);//here the error
wqry.Connection:=...
cSpacesAfter is a constant and has the value 1035. wSpaces is a local string variable. The problem is that I receive the following error when TAdoQuery is created
even it is in french, I believe you got the idea.....
If I comment the FillChar code, everything works ok. I have the usual compiler directives, nothing special. I'm using Delphi 7.
Can someone tell me what is wrong with that code?
The troublesome code is most likely this one
FillChar(wSpaces,cSpacesAfter,' ');
I'm assuming that wSpaces is of string type. A string variable is in fact nothing more than a pointer to the data structure that holds the string. You don't need to use pointer syntax because the compiler takes care of that for you.
So what this code does is overwrite the variable holding that pointer with 4 space characters and then write 1031 more spaces over the top of whatever follows the variable. In short you will completely corrupt your memory. That would explain why the FillChar works but the very next line of code dies a painful and dramatic death.
If your string indeed had space for 1035 characters your could instead write:
FillChar(wSpaces[1], cSpacesAfter, ' ');
However, if may be more idiomatic to write:
wSpaces := StringOfChar(' ', cSpacesAfter);
FillChar procedure fills out a section of storage Buffer with the same byte or character FillValue FillCount times.
It is principally used to initialise arrays of numbers. It can be used to initialise records and strings, but care should be used to avoid overwriting length fields. StringOfChar is best for filling out strings to the same character.
Are you sure wSpaces has the size enough to fit all of cSpacesAfter you write to it?
I'm trying to make some String processing routines compatible with
newest delphi version. I'm using Delphi2005 and 2007 but I'm not totally sure of the compatibility.
Here are a few samples, are they compatible with both the old and the new string type ?
( I'll use an imaginary STRING_UNICODE directive ).
a Type definition:
{$IFNDEF UNICODE_STRING}
TextBuffer = Array[0..13] Of Char;
{$ELSE}
TextBuffer = Array[0..13] Of WideChar;
{$ENDIF}
Useless or not? Is the Char type (becomes what was) a WideChar before the Unicode String, or is there still a difference?
a Function:
Function RemoveBlanks(Text: String): String;
Var
i: integer;
Begin
result := '';
For i:= 0 To Length(Text) Do
Begin
{$IFNDEF UNICODE_STRING}
If Byte(Text[i]) < 21 Then Continue;
{$ELSE}
If Word(Text[i]) < 21 Then Continue;
{$ENDIF}
If Text[i] = ' ' Then Continue;
Result := Result + Text[i];
End;
Is the Word() casting OK?
Here there is also the ' ' problem. How is the space handled
in Unicode version? Should I also use the directive to
differentiate ' ' and ' ' or will the ' ' be automatically handled
as a 2-byte blank?
a line jump:
NewLineBegin := CanReadText( aPTextBuffer, #13#10 );
How is the the second argument (#13#10) interpreted in the Unicode version? Is it compatible? Will it be translated to the byte block 00130010? If not, then should the directive be used instead with the constant #0013#0010?
The first thing to do is read Marco Cantú's paper on
Unicode: http://edn.embarcadero.com/article/38980
Question 1
Just use Char all the time with no conditional code and it will work in old and new.
Char is a special type that is an 8 bit type in old versions of Delphi and a 16 bit type in new Unicode versions.
Question 2
Char is an ordinal type so you can write if s[i]<#21.
You also need to start loops at 1 for strings since they use 1-based indexing.
Question 3
Writing #0013 is not needed, #13 is fine.
In short almost all well written code will need no changes.
Compiler Directives
In general, I'd advise you to be very wary of compiler directives. They serve their purpose, but for general use, they should probably be avoided altogether.
The first problem is that you have to compile your app and test it twice, because it is fundamentally and/or subtly different for a directive on/off.
This situation get worse for each additional directive, because you usually have to permute the combinations:
D1 On, D2 On
D1 On, D2 Off
D1 Off, D2 On
D1 Off, D2 Off
3 directives is 8 permutations... etc.
Unicode Strings
Please see: Get ready for Delphi 2009 and up when developing with Delphi 7?
It has some nice answers for you to consider.
Question 1
As said, I advise against it. I also advise against for other reasons in my answer to the above mentioned question.
More specifically:
In Delphi <2009, both lines are different.
In Delphi >=2009 both lines are effectively the same.
Question 2
Not only is this ill advised for the same reasons as Question 1, but it actually has some subtle problems.
The more precise type of Text (String) is determined by your Delphi version. So:
In Delphi <2009, the else part of your conditional casts a single character to a Word. (Probably with no ill effect.)
In Delph >=2009, the if part of your conditional casts a double-byte character to a Byte. (With loss of information.)
Also, there are some special considerations, and new support classes for 'special' characters. You'll want to look into those. Refer to: How to identify unicode keys on key press?
Question 3
I'm pretty sure that #13 will be treated as a single character, so in Delphi >=2009 where Char == WideChar, that character will take up 2 bytes.
However, again look for Linebreak constants in Delphi. System.sLinebreak was probably introduced back in the Kylix days.
Generic type Char becomes either fundamental type AnsiChar or fundamental type WideChar (read up on generic vs. fundamental types). BTW, there is UNICODE symbol $DEFINEd for you already, however there is no need to branch at all, until specific byte size is required.
Second part smells, scratch it completely. It is an abuse of typecasts and creates a need for conditional compilation artifically. To get unsigned integer character code of given Char use Ord() function instead (or as said in the other answer - use ordinal traits of Char type).
For the third part, character constants are of generic type Char already. Again, there is no need to worry about, #13 becomes either byte sized $0D or word sized $0D00 (remember about little endianess)