Lua Carrying over a value through line wrap code - string

Previously, I received help in the following link:
Lua Line Wrapping excluding certain characters
Short description of the above is that I was looking for a way to be able run a line wrap function while ignoring character count of certain characters.
Now I've come across another issue. I want to be able to carry the last colour code over to the new line. For example:
If this line #Rwere over 79 characters, I would want to #Breturn the last known colour code #Yon the line break.
Running the function I have in mind would result in:
If this line #Rwere over 79 characters, I would want to #Breturn the last known
#Bcolour code #Yon the line break.
instead of
If this line #Rwere over 79 characters, I would want to #Breturn the last known
colour code #Yon the line break.
I wish for it to do so because in many cases, the MUD will default back to the #w colour code, so it would make colourizing text rather difficult.
I've figured the easiest way to do that would be a reverse match, so I've written a reverse_text function:
function reverse_text(str)
local text = {}
for word in str:gmatch("[^%s]+") do
table.insert(text, 1, word)
end
return table.concat(text, " ")
end
and it turns:
#GThis #Yis #Ba #Mtest.
to
#Mtest. #Ba #Yis #GThis
The issue I'm running into with creating the string.match is the fact that colour codes can be in one of two formats:
#%a or #x%d%d%d
Additionally, I don't want it to return a colour code that doesn't colour, which is indicated as:
##%a or ##x%d%d%d
What's the best way to accomplish my end goal without compromising my requirements?

function wrap(str, limit, indent, indent1)
indent = indent or ""
indent1 = indent1 or indent
limit = limit or 79
local here = 1-#indent1
local last_color = ''
return indent1..str:gsub("(%s+)()(%S+)()",
function(sp, st, word, fi)
local delta = 0
local color_before_current_word = last_color
word:gsub('()#([#%a])',
function(pos, c)
if c == '#' then
delta = delta + 1
elseif c == 'x' then
delta = delta + 5
last_color = word:sub(pos, pos+4)
else
delta = delta + 2
last_color = word:sub(pos, pos+1)
end
end)
here = here + delta
if fi-here > limit then
here = st - #indent + delta
return "\n"..indent..color_before_current_word..word
end
end)
end

Related

How to truncate less than 30 characters and delete in Excel VBA?

I have an excel sheet with some rows of descriptions in a single column, what I am aiming is to get a formula that would truncate it upto certain character limit for example 30 characters and if the truncation stops at 30 character in the middle of the word then I remove that last word.
Here is the Formula that i am trying to make it work.
=LEFT(A1,FIND(" ",A1,30)-1)
Use AGGREGATE to locate the last space within the first 31 characters.
=LEFT(A2, AGGREGATE(14, 7, ROW($1:$31)/(MID(A2&" ", ROW($1:$31), 1)=" "), 1) -1)
A none loop method
=IF(LEN(A2)<30,A2,LEFT(A2,FIND("}}}",SUBSTITUTE(A2," ","}}}",30-LEN(SUBSTITUTE(LEFT(A2,30)," ",""))))-1))
Try something like this:
Put in a module at VBA Editor (ALT+F11) -> Insert New Module.
When you past this code you can call it from any cell with "=NotTruncateWord(A1;30)"
There is some ajustments to do, because it is hard to know what is a Word (something after a space?), I ask because if someone write a 35 characteres string with no space, I will consider a word and remove all?
Public Function NotTruncateWord(Value, Limit)
LastSpaceBeforeLimit = 0
FirstSpaceAfterLimit = 9999
Phrase_Lenght = Len(Value)
If Phrase_Lenght > Limit Then
For i = 1 To Phrase_Lenght
check = Mid(Value, i, 1)
If Asc(check) = 32 Then
If i < Limit Then
LastSpaceBeforeLimit = i
ElseIf i < FirstSpaceAfterLimit Then
FirstSpaceAfterLimit = i
End If
End If
Next
If LastSpaceBeforeLimit > 0 Then
NotTruncateWord = Left(Value, LastSpaceBeforeLimit)
Else
NotTruncateWord = Left(Value, Limit)
End If
Else
'no need to truncate
NotTruncateWord = Value
End If
End Function

Can you group data with similar written column headings on xlswrite, matlab?

Very new to matlab and still learning the basics. I'm trying to write a script which calculates the distance between two peaks in a waveform. That part I have managed to do, and I have used xlswrite to put the values I have obtained onto an excel file.
For each file, I have between about 50-250 columns, with just two rows: the second row has the numerical value, and the first has the column headings, copied from original excel files I extracted the data from.
Some of the columns have similar, but not identical, headings, e.g. 'green227RightEyereading3' and 'green227RightEyereading4' etc. Is there a way I can group columns with similar headings, e.g. which have the same number/colour in the heading (I.e.green227) and either 'right eye' or 'left eye', and calculate an average of their numerical values? Link to file here: >https://www.dropbox.com/s/ezpyjr3raol31ts/SampleBatchForTesting.xls?dl=0>
>[Excel_file,PathName] = uigetfile('*.xls', 'Pick a File','C:\Users\User\Documents\Optometry\Year 3\Dissertation\A-scan3');
>[~,name,ext] = fileparts(Excel_file);
>sheet = 2;
>FullXLSfile = [PathName, Excel_file];
>[number_data,txt_data,raw_data] = xlsread(FullXLSfile,sheet);
>HowManyWide = size(txt_data);
>NumberOfTitles = HowManyWide(1,2);
>xlRangeA = txt_data;
>Chickens = {'Test'};
>for f = 1:xlRangeA; %%defined as top line of cells on sheet;
>Text = xlRangeA{f};
>HyphenLocations = find(Text == '-');
>R = HyphenLocations(1,1) -1;
>Chick = Text(1:R);
>Chick = cellstr(Chick);
>B = length(Chick);
>TF = strncmp(Chickens,Chick,B);
>if any(TF == 1); %do nothing
>else
>Chickens = {Chickens;Chick};
>end
>end
Here also is a link to the file that is created when I run my entire script. The values below the headings are the calculated thickesses of the tissue I'm analysing. https://www.dropbox.com/s/4p6iu9kk75ecyzl/Choroid_Thickness.xls?dl=0
Thanks very much
If the different characters are located at the very end (or the very beginning) of the heading, you can go with strncmp buit-in function and compare only part of the string. See more here. But please, provide some code and a part of your excel file. It would help.
Also, if I am not mistaken, you are saving all the data into excel and then re-call it again in order to sort it. Maybe you should consider saving only the final result in excel, it will save you some time, especially if you want to run your script many times.
EDIT:
Here is the code I came up with. It is not the best possible solution for sure, but it works with the file you uploaded. I have omitted the unnecessary lines and variables. The code works only if the numbers of each reading have the same amount of digits. They can be 4 digits as long as every entry has 4 digits. Since in each file you have waves of the same color, the only thing that you care about is whether the reading was recorded with the left or the right eye (correct?). Based on that and the code you wrote, the comparison concerns the part of the string that contains the words "Right" or "Left", i.e. the characters between the hyphens.
[Excel_file,PathName] = uigetfile('*.xls', 'Pick a File',...
'C:\Users\User\Documents\Optometry\Year 3\Dissertation\A-scan3');
sheet = 1;
FullXLSfile = [PathName,Excel_file];
[number_data,txt_data,raw_data] = xlsread(FullXLSfile,sheet);
%% data manipulation
NumberOfTitles = length(txt_data);
TextToCompare = txt_data{1};
r1 = 1; % counter for Readings1 vector
r2 = 1; % counter for Readings2 vector
for ff = 1:NumberOfTitles % in your code xlRangeA is a cell vector not a number!
Text = txt_data{ff};
HyphenLocations = find(Text == '-');
Text = Text(HyphenLocations(1,1):HyphenLocations(1,2)); % take only the part that contains the "eye" information
TextToCompare = TextToCompare(HyphenLocations(1,1):HyphenLocations(1,2)); % same here
if (Text == TextToCompare)
Readings1(r1) = number_data(ff); % store the numerical value in a vector
r1 = r1 + 1; % increase the counter of this vector
else
Readings2(r2) = number_data(ff); % same here
r2 = r2 + 1;
end
TextToCompare = txt_data{1}; % TextToCompare re-initialized for the next comparison
end
mean_readings1 = mean(Readings1); % Find the mean of the grouped values
mean_readings2 = mean(Readings2);
I am positive that this can be done in a more efficient and delicate way. I don't know exactly what kind of calculations you want to do so I only included the mean values as an example. Inside the if statement you can also store the txt_data if you need it. Below I have also included a second way which I find more delicate. Just substitute the %%data manipulation part with the part below if you want to test it:
%% more delicate way
Text_Vector = char(txt_data);
TextToCompare2 = txt_data{1};
HyphenLocations2 = find(TextToCompare2 == '-');
TextToCompare2 = TextToCompare2(HyphenLocations2(1,1):HyphenLocations2(1,2));
Text_Vector = Text_Vector(:,HyphenLocations2(1,1):HyphenLocations2(1,2));
Text_Vector = cellstr(Text_Vector);
dummy = strcmpi(Text_Vector,TextToCompare2);
Readings1 = number_data(dummy);
Readings2 = number_data(~dummy);
I hope this helps.

How to get lines count in string?

On the whole, I get a string from JSON pair which contain "\n" symbols. For example,
"I can see how the earth nurtures its grass,\nSeparating fine grains from lumpy earth,\nPiercing itself with its own remains\nEnduring the crawling insects on its surface.\nI can see how like a green wave\nIt lifts the soil, swelling it up,\nAnd how the roots penetrate the surrounding mulch\nHappily inhaling the air in the sky.\nI can see how the light illuminates the flowers, -\nPouring itself into their tight buds!\nThe earth and the grass – continue to grow!\nDrowning the mountains in a sea of green...\nOh, The power of motion of the young,\nThe muscular pull of the plants!\nOpening up to the planet, the sun and to you,\nBreaking through the undergrowth to the fresh spring air!"
This string is a poetry for some picture.
Now I need to resize my display.newText object according to text length.
Here is how I see to do that:
Get number of lines (number of "\n" + 1, because where is no "\n" in the end)
In for loop get the longest line
Set display.newText object's size. May be using fontSize for calculating coefficient...
Question is: How to get number of lines?
To get the number of '\n' in a string, you can use string.gsub, it's used for string substitution, but it also returns the number of matches as the second return value.
local count = select(2, str:gsub('\n', '\n'))
or similar:
local _, count = str:gsub('\n', '\n')
This is apparently way faster than #Yu Hao's two solutions
local function get_line_count(str)
local lines = 1
for i = 1, #str do
local c = str:sub(i, i)
if c == '\n' then lines = lines + 1 end
end
return lines
end

MATLAB: Quickest Way To Convert Characters to A Custom Set Numbers and Back

I'm looking for a quick way to convert a large character array of lowercase letters, spaces and periods into a set of integers and vice-versa in MATLAB.
Usually I would use the double and char functions, but I would like to use a special set of integers to represent each letter (so that 'a' matches with '1', 'b' matches with '2'.... 'z' matches with 26, ' ' matches with 27, and '.' matches with 28)
The current method that I have is:
text = 'quick brown fox jumps over dirty dog';
alphabet ='abcdefghijklmnopqrstuvwxyz .';
converted_text = double(text);
converted_alphabet = double(alphabet);
numbers = nan(28,1)
for i = 1:28
numbers(converted_text(i)==converted_alphabet(i)) = i;
end
newtext = nan(size(numbers))
for i = 1:size(numbers,1)
newtext(numbers==i) = alphabet(i)
end
Unfortunately this takes quite a bit of time for large arrays, and I'm wondering if there is a quicker way to do this in MATLAB?
An easy way is to use ismember():
[~,pos] = ismember(text,alphabet)
Or use the implicit conversion carried out by -:
out = text - 'a' + 1;
note that blanks will have -64 and full stops -50, which means that you will need:
out(out == -64) = 27;
out(out == -50) = 28;
Speed considerations:
For small sized arrays the latter solution is slightly faster IF you are happy to leave blanks and full stops with their negative index.
For big arrays, on my machine 1e4 times longer, the latter solution is twice faster than ismember().
Going back:
alphabet(out)

How do I read a delimited file with strings/numbers with Octave?

I am trying to read a text file containing digits and strings using Octave. The file format is something like this:
A B C
a 10 100
b 20 200
c 30 300
d 40 400
e 50 500
but the delimiter can be space, tab, comma or semicolon. The textread function works fine if the delimiter is space/tab:
[A,B,C] = textread ('test.dat','%s %d %d','headerlines',1)
However it does not work if delimiter is comma/semicolon. I tried to use dklmread:
dlmread ('test.dat',';',1,0)
but it does not work because the first column is a string.
Basically, with textread I can't specify the delimiter and with dlmread I can't specify the format of the first column. Not with the versions of these functions in Octave, at least. Has anybody ever had this problem before?
textread allows you to specify the delimiter-- it honors the property arguments of strread. The following code worked for me:
[A,B,C] = textread( 'test.dat', '%s %d %d' ,'delimiter' , ',' ,1 )
I couldn't find an easy way to do this in Octave currently. You could use fopen() to loop through the file and manually extract the data. I wrote a function that would do this on arbitrary data:
function varargout = coltextread(fname, delim)
% Initialize the variable output argument
varargout = cell(nargout, 1);
% Initialize elements of the cell array to nested cell arrays
% This syntax is due to {:} producing a comma-separated
[varargout{:}] = deal(cell());
fid = fopen(fname, 'r');
while true
% Get the current line
ln = fgetl(fid);
% Stop if EOF
if ln == -1
break;
endif
% Split the line string into components and parse numbers
elems = strsplit(ln, delim);
nums = str2double(elems);
nans = isnan(nums);
% Special case of all strings (header line)
if all(nans)
continue;
endif
% Find the indices of the NaNs
% (i.e. the indices of the strings in the original data)
idxnans = find(nans);
% Assign each corresponding element in the current line
% into the corresponding cell array of varargout
for i = 1:nargout
% Detect if the current index is a string or a num
if any(ismember(idxnans, i))
varargout{i}{end+1} = elems{i};
else
varargout{i}{end+1} = nums(i);
endif
endfor
endwhile
endfunction
It accepts two arguments: the file name, and the delimiter. The function is governed by the number of return variables that are specified, so, for example, [A B C] = coltextread('data.txt', ';'); will try to parse three different data elements from each row in the file, while A = coltextread('data.txt', ';'); will only parse the first elements. If no return variable is given, then the function won't return anything.
The function ignores rows that have all-strings (e.g. the 'A B C' header). Just remove the if all(nans)... section if you want everything.
By default, the 'columns' are returned as cell arrays, although the numbers within those arrays are actually converted numbers, not strings. If you know that a cell array contains only numbers, then you can easily convert it to a column vector with: cell2mat(A)'.

Resources