String: replacing spaces by a number - ruby

I would like to replace every blank spaces in a string by a fixnum (which is the number of blank spaces).
Let me give an example:
s = "hello, how are you ?"
omg(s) # => "hello,3how10are2you1?"
Do you see a way (sexy if possible) to update a string like this?
Thank you Rubists :)

gsub can be fed a block for the "replace with" param, the result of the block is inserted into place where the match was found. The argument to the block is the matched string. So to implement this we capture as much whitespace as we can ( /\s+/ ) and feed that into the block each time a section is found, returning that string's length, which gets put back where the whitespace was originally found.
Code:
s = "hello, how are you ?"
res = s.gsub(/\s+/) { |m| m.length }
puts res
# => hello,3how10are2you1?

it is possible to do this via an array split : Javascript example
var s = "hello, how are you ?";
function omg( str ) {
var strArr = str.split('');
var count = 0;
var finalStr = '';
for( var i = 0; i < strArr.length; i++ ) {
if( strArr[i] == ' ' ) {
count++;
}
else
{
if( count > 0 ) {
finalStr += '' + count;
count = 0;
}
finalStr += strArr[i];
}
}
return finalStr
}
alert( omg( s ) ); //"hello,3how10are2you1?"
Lol, this seems the best it can be for javascript

Related

How to chech if the string characters have equal duplicates

I want to Check if the characters of a string have equal duplicate
if I enter :"abaababb"
returns true because I have 4 'a' and 4 'b' in that string
if I enter : "addda"
returns false because I have 2 'a' and 3 'd'
I tryed to check the duplicates but I found out I have to do it for some characters
just need to create an empty object and loop through each character and increment the value associated with the key. Keep track of the highest value so we can easily use every on the array from Object.values and check if all character counts match this value
let check = "abaababb";
let check2 = "addda";
function hasEqualCharacters( input ) {
let characters = {};
let highestCount = 0;
for( let i =0; i < input.length; i++) {
if( characters[input[i]]) {
characters[input[i]]++;
if( highestCount < characters[input[i]]) {
highestCount = characters[input[i]];
}
} else {
characters[input[i]] = 1;
}
}
return Object.values(characters).every( (charCount) => {
return charCount === highestCount;
});
}
console.log(hasEqualCharacters(check));
console.log(hasEqualCharacters(check2));
Can see it working here
https://playcode.io/1024243

InDesign Text Modification Script Skips Content

This InDesign Javascript iterates over textStyleRanges and converts text with a few specific appliedFont's and later assigns a new appliedFont:-
var textStyleRanges = [];
for (var j = app.activeDocument.stories.length-1; j >= 0 ; j--)
for (var k = app.activeDocument.stories.item(j).textStyleRanges.length-1; k >= 0; k--)
textStyleRanges.push(app.activeDocument.stories.item(j).textStyleRanges.item(k));
for (var i = textStyleRanges.length-1; i >= 0; i--) {
var myText = textStyleRanges[i];
var converted = C2Unic(myText.contents, myText.appliedFont.fontFamily);
if (myText.contents != converted)
myText.contents = converted;
if (myText.appliedFont.fontFamily == 'Chanakya'
|| myText.appliedFont.fontFamily == 'DevLys 010'
|| myText.appliedFont.fontFamily == 'Walkman-Chanakya-905') {
myText.appliedFont = app.fonts.item("Utsaah");
myText.composer="Adobe World-Ready Paragraph Composer";
}
}
But there are always some ranges where this doesn't happen. I tried iterating in the forward direction OR in the backward direction OR putting the elements in an array before conversion OR updating the appliedFont in the same iteration OR updating it a different one. Some ranges are still not converted completely.
I am doing this to convert the Devanagari text encoded in glyph based non-Unicode encoding to Unicode. Some of this involves repositioning vowel signs etc and changing the code to work with find/replace mechanism may be possible but is a lot of rework.
What is happening?
See also: http://cssdk.s3-website-us-east-1.amazonaws.com/sdk/1.0/docs/WebHelp/app_notes/indesign_text_frames.htm#Finding_and_changing_text
Sample here: https://www.dropbox.com/sh/7y10i6cyx5m5k3c/AAB74PXtavO5_0dD4_6sNn8ka?dl=0
This is untested since I'm not able to test against your document, but try using getElements() like below:
var doc = app.activeDocument;
var stories = doc.stories;
var textStyleRanges = stories.everyItem().textStyleRanges.everyItem().getElements();
for (var i = textStyleRanges.length-1; i >= 0; i--) {
var myText = textStyleRanges[i];
var converted = C2Unic(myText.contents, myText.appliedFont.fontFamily);
if (myText.contents != converted)
myText.contents = converted;
if (myText.appliedFont.fontFamily == 'Chanakya'
|| myText.appliedFont.fontFamily == 'DevLys 010'
|| myText.appliedFont.fontFamily == 'Walkman-Chanakya-905') {
myText.appliedFont = app.fonts.item("Utsaah");
myText.composer="Adobe World-Ready Paragraph Composer";
}
}
A valid approach is to use hyperlink text sources as they stick to the genuine text object. Then you can edit those source texts even if they were actually moved elsewhere in the flow.
//Main routine
var main = function() {
//VARS
var doc = app.properties.activeDocument,
fgp = app.findGrepPreferences.properties,
cgp = app.changeGrepPreferences.properties,
fcgo = app.findChangeGrepOptions.properties,
text, str,
found = [], srcs = [], n = 0;
//Exit if no documents
if ( !doc ) return;
app.findChangeGrepOptions = app.findGrepPreferences = app.changeGrepPreferences = null;
//Settings props
app.findChangeGrepOptions.properties = {
includeHiddenLayers:true,
includeLockedLayersForFind:true,
includeLockedStoriesForFind:true,
includeMasterPages:true,
}
app.findGrepPreferences.properties = {
findWhat:"\\w",
}
//Finding text instances
found = doc.findGrep();
n = found.length;
//Looping through instances and adding hyperlink text sources
//That's all we do at this stage
while ( n-- ) {
srcs.push ( doc.hyperlinkTextSources.add(found[n] ) );
}
//Then we edit the stored hyperlinks text sources 's texts objects contents
n = srcs.length;
while ( n-- ) {
text = srcs[n].sourceText;
str = text.contents;
text.contents = str+str+str+str;
}
//Eventually we remove the added hyperlinks text sources
n = srcs.length;
while ( n-- ) srcs[n].remove();
//And reset initial properties
app.findGrepPreferences.properties = fgp;
app.changeGrepPreferences.properties = cgp;
app.findChangeGrepOptions.properties =fcgo;
}
//Running script in a easily cancelable mode
var u;
app.doScript ( "main()",u,u,UndoModes.ENTIRE_SCRIPT, "The Script" );

Swift 1.2, capture character from a word

My problem is how to get character from a word
The result I needed is
DisplayChar("asd",1)
and it will display "a"
func DisplayChar(word : String, number : Int) -> String{
let i: Int = count(word)
var result = 0
result = i - (i - number)
var str = ""
var j = 0
for j = 0; j < result; j++ {
str = str + word[j]
}
return str
}
DisplayChar("xyz", 2)
This code should work
let sentence = "Hello world"
let characters = Array(sentence)
print(characters[0]) // "H"
There are a couple good solutions in this answer that may work, two good ones duplicated below.
Convert to Array
let word = "test"
var firstChar = Array(word)[0] // t
(Note: this assumes a UTF8 or ASCII encoded string, but that is likely fine for school.)
Create Your Own Extension
First an extension of String to handle subscripts:
extension String {
subscript (i: Int) -> Character {
return self[self.startIndex.advancedBy(i)]
}
subscript (i: Int) -> String {
return String(self[i] as Character)
}
subscript (r: Range<Int>) -> String {
let start = startIndex.advancedBy(r.startIndex)
let end = start.advancedBy(r.endIndex - r.startIndex)
return self[Range(start ..< end)]
}
}
Then you can just use:
let word = "test"
var firstChar = word[0] // t
Swift strings have a method called substringToIndex, "asd".substringToIndex(1) will return "a".
I'm not sure if it works on Swift 1.2, though.

Finding highest number in text file

I have a text file that contains 50 student names and scores for each student in the format.
foreName.Surname:Mark
I have figured out how to split up each line into a forename, surname and mark using this code.
string[] Lines = File.ReadAllLines(#"StudentExamMarks.txt");
int i = 0;
var items = from line in Lines
where i++ != 0
let words = line.Split(' ', '.', ':')
select new
{
foreName = words[0],
Surname = words[1],
Mark = words[2]
};
I am unsure of how i would incorporate a findMax algorithm into to find the highest mark and display the pupil with the highest mark. this as i have not used text files that often.
You can use any sorting algorithm there is a Pseudo Code available to find maximum number in any list or array..
Try this code, required just parse all files.
string[] lines = File.ReadAllLines(#"StudentExamMarks.txt");
string maxForeName = null;
string maxSurName = null;
var maxMark = 0;
for (int i = 0; i < lines.Length; i++)
{
var tmp = lines[i].Split(new char[] { ' ', '.', ':' }, StringSplitOptions.RemoveEmptyEntries);
if (tmp.Length == 3)
{
int value = int.Parse(tmp[2]);
if (i == 0 || value > maxMark)
{
maxMark = value;
maxForeName = tmp[0];
maxSurName = tmp[1];
}
}
}

Script to rename files

I have about 2200 different files in a few different folders, and I need to rename about about 1/3 of them which are in their own subfolder. Those 700 are also in various folders as well.
For example, there might be
The top-most folder is Employees, which has a few files in it, then the folder 2002 has a few, 2003 has more files, 2004 etc.
I just need to attach the word "Agreement" before the existing name of each file. So instead of it just being "Joe Schmoe.doc" It would be "Agreement Joe Schmoe.doc" instead.
I've tried googling such scripts, and I can find stuff similar to what I want but it all looks completely foreign to me so I can't understand how I'd modify it to suit my needs.
Oh, and this is for windows server '03.
I need about 2 minutes to write such script for *NIX systems (may be less), but for Windows it is a long song ... ))
I've write simple VBS script for WSH, try it (save to {script-name}.vbs, change Path value (on the first line of the script) and execute). I recommend to test script on small amount of data for the first time just to be sure if it works correctly.
Path = "C:\Users\rootDirectory"
Set FSO = CreateObject("Scripting.FileSystemObject")
Sub visitFolder(folderVar)
For Each fileToRename In folderVar.Files
fileToRename.Name = "Agreement " & fileToRename.Name
Next
For Each folderToVisit In folderVar.SubFolders
visitFolder(folderToVisit)
Next
End Sub
If FSO.FolderExists(Path) Then
visitFolder(FSO.getFolder(Path))
End If
I used to do bulk renaming with batch scripts under Windows. I know it's a snap on *nix (find . -maxdepth N -type f -name "$pattern" | sed -e 'p' -e "s/$str1/$str2/g" | xargs -n2 mv). Buf after some struggle in vain, I found out, to achieve that effect using batch scripts is almost impossible. So I turned to javascript.
With this script, you can add prefix to file names by 'rename.js "s/^/Agreement /" -r *.doc'. A caret(^) means to match the beginning. The '-r' options means 'recursively', i.e. including sub-folders. You can specify a max depth with the '-d N' option. If neither '-r' or '-d N' is given, the script does not recurse.
If you know the *nix 'find' utility, you would notice that 'find' will match the full path (not just the file name part) to specified regular expression. This behavior can be achieved by supplying the '-f' option. By default, this script will match the file name part with the given regular expression.
If you are familiar with regular expressions, complicated renaming is possible. For example, 'rename.js "s/(\d+)/[$1]/" *' which uses grouping to add brackets to number sequences in filenames.
// rename.js --- bulk file renaming utility (like *nix rename.pl)
// (c) Copyright 2012, Ji Han (hanji <at> outlook <dot> com)
// you are free to distribute it under the BSD license.
// oops... jscript doesn't have array.map
Array.prototype.map = function(f, t){
var o = Object(this);
var a = new Array(o.length >>> 0);
for (var i = 0; i < a.length; ++i){ if (i in o) a[i] = f.call(t, o[i], i, o) }
return a;
};
/// main
(function(){
if (WScript.Arguments.Length == 0){
WScript.Echo('rename "<operator>/<pattern>/<string>/[<modifiers>]" [-f] [-r] [-d <maxdepth>] [<files>]');
WScript.Quit(1);
}
var fso = new ActiveXObject('Scripting.FileSystemObject');
// folder is a Folder object [e.g. from fso.GetFolder()]
// fn is a function which operates on File/Folder object
var recurseFolder = function(folder, fn, depth, maxdepth){
if (folder.Files){
for (var e = new Enumerator(folder.Files); !e.atEnd(); e.moveNext()){
fn(e.item())
}
}
if (folder.Subfolders){
for (var e = new Enumerator(folder.SubFolders); !e.atEnd(); e.moveNext()){
fn(e.item());
if (depth < maxdepth){ arguments.callee(e.item(), fn, depth + 1, maxdepth) }
}
}
}
// expand wildcards (asterisk [*] and question mark [?]) recursively
// given path may be relative, and may contain environment variables.
// but wildcards only work for the filename part of a path.
// return an array of full paths of matched files.
// {{{
var expandWildcardsRecursively = function(n, md){
var pattern = fso.GetFileName(n);
// escape regex metacharacters (except \, /, * and ?)
// \ and / wouldn't appear in filename
// * and ? are treated as wildcards
pattern = pattern.replace(/([\[\](){}^$.+|-])/g, '\\$1');
pattern = pattern.replace(/\*/g, '.*'); // * matches zero or more characters
pattern = pattern.replace(/\?/g, '.'); // ? matches one character
pattern = pattern.replace(/^(.*)$/, '\^$1\$'); // matches the whole filename
var re = new RegExp(pattern, 'i'); // case insensitive
var folder = fso.GetFolder(fso.GetParentFolderName(fso.GetAbsolutePathName(n)));
var l = [];
recurseFolder(folder, function(i){ if (i.Name.match(re)) l.push(i.Path) }, 0, md);
return l;
}
// }}}
// parse "<operator>/<pattern>/<string>/[<modifiers>]"
// return an array splitted at unescaped forward slashes
// {{{
var parseExpr = function(s){
// javascript regex doesn't have lookbehind...
// reverse the string and lookahead to parse unescaped forward slashes.
var z = s.split('').reverse().join('');
// match unescaped forward slashes and get their positions.
var re = /\/(\\\\)*(?!\\)/g;
var l = [];
while (m = re.exec(z)){ l.push(m.index) }
// split s at unescaped forward slashes.
var b = [0].concat(l.map(function(x){ return s.length - x }).reverse());
var e = (l.map(function(x){ return s.length - x - 1 }).reverse()).concat([s.length]);
return b.map(function(_, i){ return s.substring(b[i], e[i]) });
}
// }}}
var expr = WScript.Arguments(0);
var args = [];
var options = {};
for (var i = 1; i < WScript.Arguments.Length; ++i){
if (WScript.Arguments(i).substring(0, 1) != '-'){
args.push(WScript.Arguments(i));
} else if (WScript.Arguments(i) == '-f'){
options['fullpath'] = true;
} else if (WScript.Arguments(i) == '-r'){
options['recursive'] = true;
} else if (WScript.Arguments(i) == '-d'){
options['maxdepth'] = WScript.Arguments(++i);
} else if (WScript.Arguments(i) == '--'){
continue;
} else {
WScript.Echo('invalid option \'' + WScript.Arguments(i) +'\'');
WScript.Quit(1);
}
}
if (options['maxdepth']){
var md = options['maxdepth'];
} else if (options['recursive']){
var md = 1<<31>>>0;
} else {
var md = 0;
}
var tokens = parseExpr(expr);
if (tokens.length != 4){
WScript.Echo('error parsing expression \'' + expr + '\'.');
WScript.Quit(1);
}
if (tokens[0] != 's'){
WScript.Echo('<operator> must be s.');
WScript.Quit(1);
}
var pattern = tokens[1];
var substr = tokens[2];
var modifiers = tokens[3];
var re = new RegExp(pattern, modifiers);
for (var i = 0; i < args.length; ++i){
var l = expandWildcardsRecursively(args[i], md);
for (var j = 0; j < l.length; ++j){
var original = l[j];
if (options['fullpath']){
var nouveau = original.replace(re, substr);
} else {
var nouveau = fso.GetParentFolderName(original) + '\\' + fso.GetFileName(original).replace(re, substr);
}
if (nouveau != original){
(fso.FileExists(original) && fso.GetFile(original) || fso.GetFolder(original)).Move(nouveau)
}
}
}
})();

Resources