I've needed this a few times, and only now it occured to me, that maybe Vim could do it for me. I often save files whose numbers are many, and whose names do not matter (they're temporary anyway).
I have a directory full of files: file001.txt, file002.txt ...(they're not really named "filexxx.txt" - but for the sake of discussion ...). I often save a new one, and name it for example, file434.txt. Now since that's something I do often, I'd like to skip the naming checking part.
Is there a way vim script can be made as to check for the last filexxx.txt in the directory, and save the current buffer as filexxx+1. How should I go about writing something like that ? Has anyone done something like this before ?
All advices appreciated.
Put the following in ~/.vim/plugin/nextunused.vim
" nextunused.vim
" find the next unused filename that matches the given pattern
" counting up from 0. The pattern is used by printf(), so use %d for
" an integer and %03d for an integer left padded with zeroes of length 3.
function! GetNextUnused( pattern )
let i = 0
while filereadable(printf(a:pattern,i))
let i += 1
endwhile
return printf(a:pattern,i)
endfunction
" edit the next unused filename that matches the given pattern
command! -nargs=1 EditNextUnused :execute ':e ' . GetNextUnused('<args>')
" write the current buffer to the next unused filename that matches the given pattern
command! -nargs=1 WriteNextUnused :execute ':w ' . GetNextUnused('<args>')
" To use, try
" :EditNextUnused temp%d.txt
"
" or
"
" :WriteNextUnused path/to/file%03d.extension
"
So if you're in a directory where temp0000.txt through temp0100.txt are all already used
and you do :WriteNextUnused temp%04d.txt, it will write the current buffer to temp0101.txt.
How about a script that you can shell out to? Here is a quick python script that should accomplish what you need. Save the script as "highest.py" to somewhere in your path. From VIM, get into command mode and type
:!python highest.py "file*.txt"
It returns the highest numbered file in the current directory, or a message that no files matched. It handles leading 0's and could be generalized for more complex patterns is need be.
#!/usr/bin/python
#
# Finds the highest numbered file in a directory that matches a given pattern
# Patterns are specified with a *, where the * will be where the number will occur.
#
import os
import re
import sys
highest = "";
highestGroup = -1;
if (len(sys.argv) != 2):
print "Usage: python high.py \"pattern*.txt\""
exit()
pattern = sys.argv[1].replace('*', '(\d*)')
exp = re.compile(pattern)
dirList=os.listdir(".")
for fname in dirList:
matched = re.match(exp, fname)
if matched:
if ((highest == "") or (int(matched.group(1)) > highestGroup)):
highest = fname
highestGroup = int(matched.group(1))
if (highest == ""):
print "No files match the pattern: ", pattern
else:
print highest
You can write scripts for vim in many powerful languages (depending on how your vim is compiled), such as perl, python, ruby. If it's possible for you to use a vim that's compiled with the appropriate interpreter for one of these languages, this would probably be the easiest way for you to write the script you desire.
Related
Sorry if this is a duplicate/basic question, I couldn't find any similar questions.
I have the following multiline string
my_txt = """
foo.exe\n
bar.exec\n
abab.exe\n
"""
(The newlines aren't actually written in my code, I put them there for clarity).
I want to match every file that ends with a .exe, (not .exec).
My regex was initially:
my_reg = re.compile(".+[.](?=exe$)")
my_matches = my_reg.finditer(my_txt)
I hoped that it would first find every character, go back until it found the ., and then check if the characters exe and a newline followed.
Only one match was found, and that was:
abab.exe.
I tried to mess around a bit, and changed the first line:
my_reg = re.compile(".+[.](?=exe$)",flags=re.MULTILINE).
This time, it successfully ran, returning
foo.
abab.
I thought re.MULTILINE wasn't supposed to interfere with the $ operator, or am I wrong about the $ operator/misusing something?
Thanks in advance!
You do need the multiline flag, otherwise $ will only match the absolute end of your input. You just need to match exe instead of using a lookahead:
my_reg = re.compile(".+[.]exe$", re.MULTILINE)
Output:
['foo.exe', 'abab.exe']
Demo
If you are trying to match the filename without the extension, you can put the period inside the lookahead:
my_reg = re.compile(r".+(?=\.exe$)", re.MULTILINE)
Output:
['foo', 'abab']
Demo
I am making a small project in python that lets you make notes then read them by using specific arguments. I attempted to make an if statement to check if the string has a comma in it, and if it does, than my python file should find the comma then find the character right below that comma and turn it into an integer so it can read out the notes the user created in a specific user-defined range.
If that didn't make sense then basically all I am saying is that I want to find out what line/bit of code is causing this to not work and return nothing even though notes.txt has content.
Here is what I have in my python file:
if "," not in no_cs: # no_cs is the string I am searching through
user_out = int(no_cs[6:len(no_cs) - 1])
notes = open("notes.txt", "r") # notes.txt is the file that stores all the notes the user makes
notes_lines = notes.read().split("\n") # this is suppose to split all the notes into a list
try:
print(notes_lines[user_out])
except IndexError:
print("That line does not exist.")
notes.close()
elif "," in no_cs:
user_out_1 = int(no_cs.find(',') - 1)
user_out_2 = int(no_cs.find(',') + 1)
notes = open("notes.txt", "r")
notes_lines = notes.read().split("\n")
print(notes_lines[user_out_1:user_out_2]) # this is SUPPOSE to list all notes in a specific range but doesn't
notes.close()
Now here is the notes.txt file:
note
note1
note2
note3
and lastly here is what I am getting in console when I attempt to run the program and type notes(0,2)
>>> notes(0,2)
jeffv : notes(0,2)
[]
A great way to do this is to use the python .partition() method. It works by splitting a string from the first occurrence and returns a tuple... The tuple consists of three parts 0: Before the separator 1: The separator itself 2: After the separator:
# The whole string we wish to search.. Let's use a
# Monty Python quote since we are using Python :)
whole_string = "We interrupt this program to annoy you and make things\
generally more irritating."
# Here is the first word we wish to split from the entire string
first_split = 'program'
# now we use partition to pick what comes after the first split word
substring_split = whole_string.partition(first_split)[2]
# now we use python to give us the first character after that first split word
first_character = str(substring_split)[0]
# since the above is a space, let's also show the second character so
# that it is less confusing :)
second_character = str(substring_split)[1]
# Output
print("Here is the whole string we wish to split: " + whole_string)
print("Here is the first split word we want to find: " + first_split)
print("Now here is the first word that occurred after our split word: " + substring_split)
print("The first character after the substring split is: " + first_character)
print("The second character after the substring split is: " + second_character)
output
Here is the whole string we wish to split: We interrupt this program to annoy you and make things generally more irritating.
Here is the first split word we want to find: program
Now here is the first word that occurred after our split word: to annoy you and make things generally more irritating.
The first character after the substring split is:
The second character after the substring split is: t
I am trying to open a file that has a random time date stamp as part of its name. Most of the filename is known eg filename = 2017_01_23_624.txt is my test name. The date and numbers is the part I am trying to replace with something unknown as it will change.
My question relates to opening an existing file and not creating a new filename. The filenames are created by a separate program and I must be able to open them. I also want to change them once they are open.
I have been trying to construct the filename string as follow but get invalid syntax.
filename = "testfile" + %s + ".txt"
print(filename)
fo = open(filename)
You can't open a file with a partial filename containing a wildcard for it to match. What you would have to do it look at all the files in your directory and pick the one that matches best.
Simple example:
import os
filename = "filename2017_" # known section
direc = r"directorypath"
matches = [ fname for fname in os.listdir(direc) if fname.startswith(filename) ]
print(matches)
You can however use the glob module (Thanks to bzimor) to pattern match your files. See glob docs for more info.
import glob, os
# ? - represents any single character in the filename
# * - represents any number of characters in the filename
direc = r"directorypath"
pattern = 'filename2017-??-??-*.txt'
matches = glob.glob(os.path.join(direc, pattern))
print(matches)
Similar to first solution is that you still get back a list of filenames to choose from to then open. But with the glob module you can more accurately match your files if you so need. It all depends on how tight you want it to be.
When editing a text file, the default character-counting function in Sublime 3 counts a newline as one character, irrespective of whether the line ends in LF or CR,LF. I cannot find a setting to give me the correct count for a text file with CR,LF line endings.
I've tried installing the WordCount package, but it has the same issue. Setting the preference
char_ignore_whitespace : true
does not change the behaviour.
One could argue that Sublime's behaviour is incorrect since (for the files I am working with) the newline constitutes two characters, not one.
The reason I would like the count to include the CR in the character count (i.e. a newline is 2 characters) is so that I can use Sublime to help debug some code that is using ftell/fseek. As it stands, I have to keep adding the line count to the character count to get the correct byte position in the file (when selecting all text from the beginning of the file to the point of interest).
Is there a setting I am missing? Is there a different package that can be used?
EDIT: I noticed that Notepad++ correctly reports the character count for such files, but I prefer to use Sublime :)
EDIT2: I found some code here (Is it possible to show the exact position in Sublime Text 2?) that works in Sublime 3, but also counts two-character newlines incorrectly.
I modified the code in the link above to crudely compensate the the missing end-of-line counts. The code below simply adds the number of lines (zero-based) to the character position and displays this as an alternative position (in case a unix-style file is open, in which case the compensation is not required).
This is admittedly crude, and not intelligent enough to determine what type of line ending the file has. Maybe someone else has a better idea?
import sublime, sublime_plugin
class PositionListener(sublime_plugin.EventListener):
def on_selection_modified(self,view):
text = "Position: "
sels = view.sel()
for s in sels:
if s.empty():
row, col = view.rowcol(s.begin())
text += str(s.begin())
text += " [" + str(s.begin() + row) + "]"
else:
text += str(s.begin()) + "-" + str(s.end())
row, col = view.rowcol(s.begin())
text += " [" + str(s.begin() + row) + "-"
row, col = view.rowcol(s.end())
text += str(s.end() + row) + "]"
view.set_status('exact_pos', text)
I need to get help for a pattern in Lua stopping to read after a line break.
My code:
function getusers(file)
local list, close = {}
local user, value = string.match(file,"(UserName=)(.*)")
print(value)
f:close()
end
f = assert(io.open('file2.ini', "r"))
local t = f:read("*all")
getusers(t)
--file2.ini--
user=a
UserName=Tom
Password=xyz
UserName=Jane
Output of script using file2.ini:
Tom
Password=xyz
UserName=Jane
How to get the pattern to stop after it reaches the end of line?
You can use the pattern
"(UserName=)(.-)\n"
Note that besides the extra \n, the lazy modifier - is used instead of *.
As #lhf points out, make sure the file ends with a new line. I think you can append a \n to the string manually before matching.