Multiline string literal in Ada - string

How can I create a string in Ada containing newlines, whose definition also has those newlines?
I've tried with 0..2 backslashes at the end of the line, but none of that compiles:
usage_info : String := "\
This should be the first line
and both the definition and the output
should contain newlines.";
In PHP this would be:
<<<BLOCK
1
2
3
BLOCK;
In C++ this would be:
const std::string s = "\
1
2
3";
In C#, it would be:
const string s =
#"1
2
3";

From what I know, Ada , like Java, does not support multiline literal.
The only thing I see is something like this:
usage_info : String := "This should be the first line" & CR & LF
& "and both the definition and the output" & CR & LF
& "should contain newlines.";
Of course, you need to with and use Ada.Characters.Latin_1 to make these constants visible.

A complement to Frédéric Praca answer:
Depending on your needs, you can use ASCII package instead of Ada.Characters.* (such as Latin_1, Latin_9, Wide_Latin_.. etc.). ASCII can not be with'ed since it is not a package, so you'll have to prefix everything (or define "aliases" using renames)
declare
flex : constant String := "Foo" & ASCII.CR & "bar" & ASCII.LF;
flux : constant String := "Foo" & ASCII.CR
& "bar" & ASCII.LF;
begin
-- do stuff
null;
end;
One could define a custom & operator to use it as a new line insertion point. But ... how useful is it ?
function Foo (Left, Right : String) return String renames "&";
function Boo (Left : String; Right : Character) return String renames "&";
function "&" (Left, Right : String) return String is begin
return Foo (
Boo (Left, ASCII.LF),
Right);
end "&";
Ada.Text_IO.Put_Line("Foo" &
"bar");

Related

Ada - Type out a string using S'length

The problem is simple and can be solved by a simple Get_Line, but the problem suggests otherwise.
A subprogram has to be created. The subprogram should only have one parameter (which is the string) and return length of the string (as an integer) of course. To get the length of a string you could do S'Length and you have to use the length of the string when you type out in your main program.
For instance:
Type a string containing 3 letters: Wow
You typed the string: Wow
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure String_Program is
function String_Length (S : in String) return Integer is
Res : Integer;
begin
Res := S'Length;
return Res;
end String_Length;
S : String (1 .. 3);
begin
Put("Type a string containing 3 letters: ");
Get(S);
Put("You typed the string: ");
Put(String_Length(S), Width => 1);
end String_Program;
I've done as instructed but my program types out the actual number corresponding the amount of characters there are in the string. So when I type "Hey" it will type out "3". And I know why it is like that because I'm returning the actual length of the string as an integer. How do I type the actual string out and not the number? After all I'm returning an integer so it will be tough.
Help is greatly appreciated!
with Ada.Text_IO; use Ada.Text_IO;
procedure String_Program is
function String_Length (S : in String) return Natural is
begin
return S'Length;
end String_Length;
S : String (1 .. 3);
begin
Put ("Type a string containing 3 letters: ");
Get (S);
Put ("You typed the string: ");
-- Put string S to standard output one character at a time
-- using String_Length.
for Offset in 0 .. String_Length (S) - 1 loop
Put (S (S'First + Offset));
end loop;
New_Line;
end String_Program;
Have you been introduced to declare blocks yet, as a way of handling unknown length strings?
Because the problem statement
A subprogram has to be created. The subprogram should only have one parameter (which is the string) and return length of the string (as an integer) of course. To get the length of a string you could do S'Length and you have to use the length of the string when you type out in your main program.
by not mentioning a specific string length, is screaming loud and clear for a declare block in the main program...
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure String_Program is
function String_Length (S : in String) return Integer is
begin
return S'Length;
end String_Length;
begin
Put("Type a string : ");
declare
S : String := Get_Line;
begin
Put( "Your string : " & S & " has ");
Put( String_Length(S), Width => 1);
Put_Line(" characters");
end;
end String_Program;
However, remember your professor undoubtedly watches Stack Overflow, so you can't simply use this program as it is.

Golang Determine if String contains a String (with wildcards)

With Go, how would you determine if a string contains a certain string that includes wildcards? Example:
We're looking for t*e*s*t (the *'s can be any characters and any length of characters.
Input True: ttttteeeeeeeesttttttt
Input False: tset
Use the regexp package by converting the * in your pattern to the .* of regular expressions.
// wildCardToRegexp converts a wildcard pattern to a regular expression pattern.
func wildCardToRegexp(pattern string) string {
var result strings.Builder
for i, literal := range strings.Split(pattern, "*") {
// Replace * with .*
if i > 0 {
result.WriteString(".*")
}
// Quote any regular expression meta characters in the
// literal text.
result.WriteString(regexp.QuoteMeta(literal))
}
return result.String()
}
Use it like this:
func match(pattern string, value string) bool {
result, _ := regexp.MatchString(wildCardToRegexp(pattern), value)
return result
}
Run it on the Go PlayGround.
Good piece of code. I would offer one minor change. It seems to me that if you're using wildcards, then the absence of wildcards should mean exact match. To accomplish this, I use an early return....
func wildCardToRegexp(pattern string) string {
components := strings.Split(pattern, "*")
if len(components) == 1 {
// if len is 1, there are no *'s, return exact match pattern
return "^" + pattern + "$"
}
var result strings.Builder
for i, literal := range components {
// Replace * with .*
if i > 0 {
result.WriteString(".*")
}
// Quote any regular expression meta characters in the
// literal text.
result.WriteString(regexp.QuoteMeta(literal))
}
return "^" + result.String() + "$"
}
Run it on the Go Playground

Split large string

I have a long text which needs to be converted to small strings so I can include it to an AutoIt script. If I include multi-line text it shows error unterminated string. So I should have:
"numbercharswillbe10" &_ "othernumbersofcharwillbe10" &_ etc..
How can I split it with & _ -delimiters?
String concatenation
As per Documentation - Language Reference - Operators:
& Concatenates/joins two strings.
&= Concatenation assignment.
Example:
Global $g_sText = "Long " & "string " & "here." & #CRLF
$g_sText &= "More text." & #CRLF
ConsoleWrite($g_sText)
Multi line statements
As per Documentation - Language Reference - Comments (emphasis added, as it causes mentioned "unterminated string" error):
Although only one statement per line is allowed, a long statement can span multiple lines if an underscore "_" preceded by a blank is placed at the end of a "broken" line. String definition cannot be split in several lines, concatenation need to be used.
Example:
Global Const $g_sText = "Long " & _
"string " & _
"here." & _
#CRLF & _
"More text." & _
#CRLF
ConsoleWrite($g_sText)
Double-quotes
As per Documentation - FAQ - Double quotes:
If you want to use double-quotes inside a string then you must "double them up". So for every one quote you want you should use two. ...
or use single quotes instead ...
Examples available from source.
Defaults and limits
As per Documentation - Appendix - Limits/defaults:
4095 Maximum size for a line of script.
2,147,483,647 Maximum string length.
As per Documentation - Language Reference - Datatypes - Strings:
All AutoIt strings use UTF-16 (in fact and more precisely UCS-2) encoding.
As per Documentation - Intro - Unicode Support:
There are a few parts of AutoIt that don't yet have full Unicode support. These are:
Send and ControlSend - Instead, Use ControlSetText or the Clipboard functions.
Console operations are converted to ANSI.
Alternatives
Alternatives to hard coding include ClipGet() and FileRead().
Text from clipboard
Example (select and copy text CTRL + C first):
Global Const $g_sText = ClipGet()
ConsoleWrite($g_sText & #CRLF)
Text from file
Example (create C:\my_long_string.txt first):
#include <FileConstants.au3>
Global Const $g_sFile = 'C:\my_long_string.txt'
Global Const $g_sText = _TextFromFile($g_sFile)
ConsoleWrite($g_sText & #CRLF)
Func _TextFromFile(Const $sFile)
Local $hFile = FileOpen($sFile, $FO_READ + $FO_UTF8_NOBOM)
Local Const $sData = FileRead($hFile)
FileClose($hFile)
Return $sData
EndFunc
Split string
Alternatives to hard coded manual string splitting include StringSplit(), _StringExplode() (related) and StringMid().
Structural
StringSplit() splits a string into array of:
individual characters (on empty delimiter),
words (on space delimiter) or
lines (on #CRLF, #LF or #CR delimiter).
Equal length
StringMid() returns part of a string. Can be used to split into parts of equal length. Example (no error checking, select and copy text CTRL + C first):
#include <Array.au3>
Global Const $g_iSize = 10
Global Const $g_sText = ClipGet()
Global Const $g_aArray = _StringSplitEqual($g_sText, $g_iSize)
_ArrayDisplay($g_aArray)
Func _StringSplitEqual(Const $sText, Const $iSize = 1)
Local Const $iLength = StringLen($sText)
Local Const $iParts = Ceiling($iLength / $iSize)
Local Const $iRest = -1; $iLength - ($iSize * Floor($iLength / $iSize))
Local $iStart = 0
Local $iCount = 0
Local $aArray[$iParts]
For $i1 = 0 To $iParts - 1
$iStart = ($i1 * $iSize) + 1
$iCount = ($i1 < $iParts - 1) ? $iSize : ($iRest ? $iRest : $iSize)
$aArray[$i1] = StringMid($sText, $iStart, $iCount)
Next
Return $aArray
EndFunc
Join string
As per documentation:
_ArrayToStringPlaces the elements of a 1D or 2D array into a single string, separated by the specified delimiters
Example (add _StringSplitEqual() and select and copy text CTRL + C first):
#include <Array.au3>
Global Const $g_iSize = 10
Global Const $g_sStart = '$sText = "'
Global Const $g_sEnd = '"' & #CRLF
Global Const $g_sDelimiter = '" _' & #CRLF & ' & "'
Global Const $g_sText = StringReplace(ClipGet(), #CRLF, '')
Global Const $g_aArray = _StringSplitEqual($g_sText, $g_iSize)
Global $g_sResult = _ArrayToString($g_aArray, $g_sDelimiter)
$g_sResult = $g_sStart & $g_sResult & $g_sEnd
ConsoleWrite($g_sResult)
Returns:
$sText = "AutoIt v3 " _
& "is a freew" _
& "are BASIC-" _
& "like scrip" _
& "ting langu" _
& "age design" _
& "ed for aut" _
& "omating th" _
& "e Windows " _
& "GUI and ge" _
& "neral scri" _
& "pting."

D: how to remove last char in string?

I need to remove last char in string in my case it's comma (","):
foreach(line; fcontent.splitLines)
{
string row = line.split.map!(a=>format("'%s', ", a)).join;
writeln(row.chop.chop);
}
I have found only one way - to call chop two times. First remove \r\n and second remove last char.
Is there any better ways?
import std.array;
if (!row.empty)
row.popBack();
As it usually happens with string processing, it depends on how much Unicode do you care about.
If you only work with ASCII it is very simple:
import std.encoding;
// no "nice" ASCII literals, D really encourages Unicode
auto str1 = cast(AsciiString) "abcde";
str1 = str1[0 .. $-1]; // get slice of everything but last byte
auto str2 = cast(AsciiString) "abcde\n\r";
str2 = str2[0 .. $-3]; // same principle
In "last char" actually means unicode code point (http://unicode.org/glossary/#code_point) it gets a bit more complicated. Easy way is to just rely on D automatic decoding and algorithms:
import std.range, std.stdio;
auto range = "кириллица".retro.drop(1).retro();
writeln(range);
Here retro (http://dlang.org/phobos/std_range.html#.retro) is a lazy reverse iteration function. It takes any range (unicode string is a valid range) and returns wrapper that is capable of iterating it backwards.
drop (http://dlang.org/phobos/std_range.html#.drop) simply pops a single range element and ignores it. Calling retro again will reverse the iteration order back to normal, but now with the last element dropped.
Reason why it is different from ASCII version is because of nature of Unicode (specifically UTF-8 which D defaults to) - it does not allow random access to any code point. You actually need to decode them all one by one to get to any desired index. Fortunately, D takes care of all decoding for you hiding it behind convenient range interface.
For those who want even more Unicode correctness, it should be possible to operate on graphemes (http://unicode.org/glossary/#grapheme):
import std.range, std.uni, std.stdio;
auto range = "abcde".byGrapheme.retro.drop(1).retro();
writeln(range);
Sadly, looks like this specific pattern is not curently supported because of bug in Phobos. I have created an issue about it : https://issues.dlang.org/show_bug.cgi?id=14394
NOTE: Updated my answer to be a bit cleaner and removed the lambda function in 'map!' as it was a little ugly.
import std.algorithm, std.stdio;
import std.string;
void main(){
string fcontent = "I am a test\nFile\nwith some,\nCommas here and\nthere,\n";
auto data = fcontent
.splitLines
.map!(a => a.replaceLast(","))
.join("\n");
writefln("%s", data);
}
auto replaceLast(string line, string toReplace){
auto o = line.lastIndexOf(toReplace);
return o >= 0 ? line[0..o] : line;
}
module main;
import std.stdio : writeln;
import std.string : lineSplitter, join;
import std.algorithm : map, splitter, each;
enum fcontent = "some text\r\nnext line\r\n";
void main()
{
fcontent.lineSplitter.map!(a=>a.splitter(' ')
.map!(b=>"'" ~ b ~ "'")
.join(", "))
.each!writeln;
}
Take a look, I use this extension method to replace any last character or sub-string, for example:
string testStr = "Happy holiday!";<br>
Console.Write(testStr.ReplaceVeryLast("holiday!", "Easter!"));
public static class StringExtensions
{
public static string ReplaceVeryLast(this string sStr, string sSearch, string sReplace = "")
{
int pos = 0;
sStr = sStr.Trim();
do
{
pos = sStr.LastIndexOf(sSearch, StringComparison.CurrentCultureIgnoreCase);
if (pos >= 0 && pos + sSearch.Length == sStr.Length)
sStr = sStr.Substring(0, pos) + sReplace;
} while (pos == (sStr.Length - sSearch.Length + 1));
return sStr;
}
}

String insertion

I have problems with inserting string variable inside text.
string p="http://www.google.com" ;
system("c:\\progra~1\\intern~1\\iexplore.exe \"http://www.google.com\"");
I need a way to use p instead of "http://www.google.com\"
I tried
system("c:\\progra~1\\intern~1\\iexplore.exe \%p\"");
but it doesn't work. I'm not very good with strings so probably that's the prob.
In C++ you can use the + operator to concatenate strings:
system((std::string("c:\\progra~1\\intern~1\\iexplore.exe ") + p).data());
In this case this is a bit hard to read, so you're better off creating the string before hand.
A better way would be to use stringstream:
#include <sstream>
std::stringstream sstr;
std::string p = "http://www.google.com";
sstr << "c:\\progra~1\\intern~1\\iexplore.exe " << p;
system(sstr.str().data());
Lets assume c#
string blammy = #"c:\progra~1\intern~1\iexplore.exe";
string finalAnswer;
string pikaPika = #"http://www.google.com";
finalAnswer = blammy + " " + pikaPika;
system(finalAnswer);

Resources